How to write unison skill/item plugins

DoubleX

Just a nameless weakling
Veteran
Joined
Jan 2, 2014
Messages
1,787
Reaction score
939
First Language
Chinese
Primarily Uses
N/A
This topic aims to share my understanding about unison skill/item plugins and explore some ways to write some of them designed for respective battle systems.


The 1st post focuses on covering stuffs that can be common to all unison skill/item plugins, while each subsequent post will concentrate on using examples to explore the implementation of unison skill/item plugins into each specific battle system.


When reading this post, you're assumed to have at least decent battle related plugin development proficiency(experienced plugin developer having written dozens of decent battle related plugins with decent code qualities), although those not being this capable yet can still follow at least some of the contents, albeit with extra efforts :)


Definitions

An Unison Skill/Item is a skill/item needing more than 1 battlers to use it together.


Unison Battlers for an Unison Skill/Item are all those needed to use that skill/item together.


At the players' level, all Unison Battlers will behave like using the same Unison Skill/Item at the exact same frames.


The below 2 videos showcases what the above means:


DoubleX RMMV Unison Item Default


DoubleX RMMV Unison Item YEP_X_BattleSysCTB


So it's natural to think of an Unison Skill/Item to be inputted by 1 of the Unison Battlers and executed by all of them.


Due to the below 2 of the most fundamental Scene_Battle based battle foundations(you can try to break them if you feel/think you're a gifted plugin developer :D ), however(too advanced to be explained here):


1. Only 1 battler can execute actions at the exact same frame.


2. Only 1 action can be executed at the exact same frame.


Only 1 of the Unison Battlers will actually use the Unison Skill/Item.


As in the default RMMV battle system, the one inputting the skill/item is the one executing that skill/item, Unison Skills/Items should behave the same here. This lead to the below definitions:


1. The Unison Invoker of an Unison Skill/Item is the Unison Battler actually inputting and executing the Unison Skill/Item.


2. The Unison Invokees of an Unison Skill/Item are the Unison Battlers other than the Unison Invoker.


Unison Skill/Item Cost/Action Slot Mechanisms



 





As mentioned in Definitions, only the Unison Invoker is actually inputting and using the Unison Skill/Item, so only that battler will pay an action slot and the cost of that skill/item if nothing else's changed.


But as Unison Skill/Item is one needing all Unison Battlers to use it together, all Unison Invokees should pay an action slot and the cost of that skill/item too, in order to use it.


Unison Battler Recognitions



 





Recognizing the Unison Battlers for an Unison Skill/Item can be as simple as letting unison skill/item plugin users to add a new skill/item notetag like this(DoubleX RMMV Unison Item Config v101b):



 









* 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








Unison Skill/Item Cost Implementations

A natural implementation for the skill/item cost is to ask all Unison Battlers to say the same skill/item cost upon using it(DoubleX RMMV Unison Item Config v100f):



 









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



To let different Unison Battlers pay different skill/item costs, some new configurations can be added(DoubleX RMMV Unison Item Config v101b):

* 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



And the below implementations can be added(DoubleX RMMV Unison Item Config v101b):

GBB.skillMpCost = Game_BattlerBase.prototype.skillMpCost;
Game_BattlerBase.prototype.skillMpCost = function(skill) {
// Returns corresponding mp cost in <unison item actor mp cost: costs>
if (this.isActor()) {
var index = skill.meta.unisonItemActors.indexOf(this.actorId());
if (index >= 0) {
var mpCost = skill.meta.unisonItemActorMpCosts[index];
if (!isNaN(mpCost)) { return Math.floor(mpCost * this.mcr); }
}
}
//
return GBB.skillMpCost.apply(this, arguments);
}; // Game_BattlerBase.prototype.skillMpCost

GBB.skillTpCost = Game_BattlerBase.prototype.skillTpCost;
Game_BattlerBase.prototype.skillTpCost = function(skill) {
// Returns corresponding tp cost in <unison item actor tp cost: costs>
if (this.isActor()) {
var index = skill.meta.unisonItemActors.indexOf(this.actorId());
if (index >= 0) {
var tpCost = skill.meta.unisonItemActorTpCosts[index];
if (!isNaN(tpCost)) { return tpCost; }
}
}
//
return GBB.skillTpCost.apply(this, arguments);
}; // Game_BattlerBase.prototype.skillTpCost








Unison Skill/Item Action Slot Implementations

The goal of implementing the Unison Skill/Item action slot mechanisms is to ensure all Unison Invokees will also pay at least 1 action slot in order to behave like executing the Unison Skill/Item together with the Unison Invoker. However, how this can be implemented heavily depends on the action input mechanisms of the battle system the unison skill/item plugins are working with.


For example:


- In the default RMMV battle system, each Unison Skill/Item will have to reserve some empty action slots from each Unison Invokee by making those action slots inaccessible by the players, thus making those action slots not being able to store actions. It means an Unison Skill/Item can only be usable when all Unison Invokees have enough empty action slots to be reserved by that Unison Skill/Item.


- In an ATB/CTB/ITB system, there will be 2 types of Unison Skills/Items:


1. A Synchronous Unison Skill/Item is an Unison Skill/Item needing all Unison Battlers to have enough empty action slots for it to be inputable.


2. An Asynchronous Unison Skill/Item is an Unison Skill/Item needing any Unison Battlers to have enough empty action slots for it to be inputable, and all Unison Battlers to have enough empty action slots for it to be executed.


For instance, the action slot implementations for a Synchronous Unison Skill/Item in an ATB system where no battler can have more than 1 action slots at the same time(the implementations will be significantly more complicated and convoluted with this restriction removed) can be as simple as checking whether all Unison Battlers are inputable and make all Unison Invokees to become not inputable when the Unison Invoker has inputted the Unison Skill/Item.


These 2 cases are sufficient to show how much the Unison Skill/Item action slot implementations depend on the action input mechanisms of the battle system the unison skill/item plugins are working with. Therefore it's be more desirable to discuss this for each battle system example in each subsequent reply.


(On a side note: All Unison Skills/Items in the default RMMV battle system are Synchronous Unison Skills/Items, as all battlers must completely input all their action slots before any Unison Skill/Item can be executed.)


P.S.: The item usability check in the item window can be outsourced to the battler skill/item usability check this way(DoubleX RMMV Unison Item Config v101b):



 









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 (SceneManager.scene.constructor !== Scene_Battle) {
return WIL.isEnabled.apply(this, arguments);
}
var actor = BattleManager.actor();
return actor && actor.canUse(item);
//
}; // Window_ItemList.prototype.isEnabled










Unison Skill/Item Damage Formula

As the Unison Invoker is the only battler actually using the Unison Skill/Item, its damage formula will only use the stats of that battler if nothing else's changed.


But Unison Skills/Items are supposed to be used by all Unison Battlers, so all their stats, not just those of the Unison Invoker, should be used in the damage formula of the Unison Skill/Item.


While the damage formula can be coded to include stats of Unison Invokees as well via $gameActors.actor(actorId).stat, this approach can needlessly and quickly complicate the damage formula.


An alternative of this can be something like these(DoubleX RMMV Unison Item Config v101b):



 





Parameter -



 










* @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 the plugin js file directly
* @default avg



Notetags -

* 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 the plugin js file
* directly
* - function must be a battler function name included in
* FUNCTIONS, which must be edited by opening the 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 the plugin js file
* directly



Configurations -

/* 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 property 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


}






Which can be implemented this way(DoubleX RMMV Unison Item Config v101b):

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


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

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

        });
    }







Battle Log Window

The default RMMV battle log window shows who're using the actions to be executed.


As only the Unison Invoker will actually use the Unison Skill/Item, the default RMMV battle log window will only show the name of the Unison Invoker if nothing else's changed.


So it'd be desirable to let unison skill/item plugin users to change the battle log window to show the name of all Unison Battlers.


1 such example is this(DoubleX RMMV Unison Item Config v101b):



 










* @param showAllUnisonBattlers
* @desc Sets if the battlelog will show all unison battlers instead of only
* the unison invoker
* @default true



Which can be implemented like this(DoubleX RMMV Unison Item Config v101b):

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







Unison Skill/Item Plugin Structure

As mentioned, the Unison Skill/Item action slot implementations depend on the action input mechanisms of the battle system the unison skill/item plugins to work with.


It alone means it'd be more desirable to make an unison skill/item plugin for each specific battle system, rather than 1 trying to target all battle systems, since the Unison Skill/Item action slot implementations is the core Unison Skill/Item mechanism.


On the other hand, some uinson skill/item plugin implementations doesn't depend much on any battle system, like the Unison Skill/Item cost, damage formula and perhaps the battle log window.


It alone implies it'd be more desirable to make an unison skill/item plugin for all battle systems.


Combining, an excellent enough compromise is to make 1 unison skill/item plugin implementing all those common parts, and make 1 unison skill/item plugin for each specific battle system implementing all parts heavily depending on that battle system. All the latters will need the former to work.


As an example:


- DoubleX RMMV Unison Item Config stores all configurations and implements the Unison Skill/Item cost, damage formula and the battle log window.


- DoubleX RMMV Unison Item Default, which needs DoubleX RMMV Unison Item Config and targets the default RMMV battle system, implements the action input mechanisms that works with that battle system.


- DoubleX RMMV Unison Item YEP_X_BattleSysCTB, which DoubleX RMMV Unison Item Config, DoubleX RMMV Unison Item Default(as YEP_X_BattleSysCTB can be disabled on the fly) and targets YEP_X_BattleSysCTB, implements the action input mechanisms that works with that battle system.


That's all for now. Later I'll add subsequent replies showing how unison skill/item plugins can be worked with various battle system examples ;)
 
Last edited by a moderator:

Chaos17

Dreamer
Veteran
Joined
Mar 13, 2012
Messages
1,311
Reaction score
485
First Language
French
Are you looking for this ?




You can combine it with Yanfly action sequence to make look like this :
 

DoubleX

Just a nameless weakling
Veteran
Joined
Jan 2, 2014
Messages
1,787
Reaction score
939
First Language
Chinese
Primarily Uses
N/A
Are you looking for this ?





You can combine it with Yanfly action sequence to make look like this :
So far that system is noticeably different from what is topic's about.


Basically, that one(dual tech) is that, if skill A and skill B are inputted, they can be combined and become skill C instead.


Which skill A and skill B can be combined to which skill C can be set by users.


What this topic's about(Unison Skill/Item) is that, some skill D needs more than 1 inputable battlers, say, b1, b2, b3, ..., bn to be usable.


Which skill D needs which inputable battlers b1, b2, b3, ..., bn can be set by users.


The key difference in the implementation is that, dual tech will typically check the skill combinations after each skill/item's inputted(or all skills/items are inputted for the default RMMV battle system), while Unison Skill/Item will typically check its Unison Battlers before that skill/item's inputted(and for some Asynchronous Unison Skills/Items, during that skill/item's inputting progress in some ATB systems).


In my opinion, these 2 systems are different enough to be treated separately :)
 
Last edited by a moderator:

DoubleX

Just a nameless weakling
Veteran
Joined
Jan 2, 2014
Messages
1,787
Reaction score
939
First Language
Chinese
Primarily Uses
N/A
Let's talk about how to implement the action slot mechanisms for unison skill/item plugins working with the default RMMV battle system. For now, I'll focus on unison skills/items used by non autobattle actors.


You're assumed to have:


- Solid understanding to the default RMMV battle flow implementations


- Decent battle related plugin development proficiency(experienced plugin developer having written dozens of decent battle related plugins with decent code qualities)


Let's check this video again before we start:










Battle modification requirements


Recall that all Unison Skills/Items in the default RMMV battle system are Synchronous Unison Skills/Items.


 




Action Execution Changes



 

1. As only the Unison Invoker will execute the Unison Skill/Item, all the Unison Invokees only need to pay the Unison Skill/Item costs after executing that Unison Skill/Item. The implementation of this is already covered in the 1st post in this topic.


2. To clearly show all the unison battlers of the Unison Skill/Item when it's executing, the log window should show all their names. The implementation of this is already covered in the 1st post in this topic.


Action Usability Changes


1. As all Unison Battlers need to be able to use the Unison Skill/Item while only the Unison Invoker actually uses it, the action usability check of the Unison Invoker upon both inputting and executing that Unison Skill/Item needs to check all Unison Battlers' usability of that Unison Skill/Item.


Action Input Changes


1. Right after an Unison Invoker finished inputting the Unison Skill/Item, all Unison Invokees of that Unison Skill/Item needs to reserve an action slot for that Unison Skill/Item.


2. Right after an action slot of an Unison Invoker's been replaced the previous Unison Skill/Item with a new skill/item(or right after an previously inputted action slot with an Unison Skill/Item's pointed to), all other Unison Invokees' reserved action slots for that Unison Skill/Item need to be "freed".


3. If proceeding to the next action slot would point to a reserved one for an Unison Skill/Item, the next action slot of that reserved one, if any(or the 1st action slot of the next inputable actor if the last action slot's reached), should be pointed to instead. Repeat until there's no more next action slots(then the Action Input Phase should be ended) or the next one isn't reserved for Unison Skill/Items.


4. If proceeding to the prior action slot would point to a reserved one for an Unison Skill/Item, the prior action slot of that reserved one, if any(or the last action slot of the prior inputable actor if the 1st action slot's reached), should be pointed to instead. Repeat this until there's no more prior action slots(then the party command window should be shown) or the prior one isn't reserved for Unison Skill/Items.








Action Slot Mechanism Implementations

Invariants



 





Recall that in the default RMMV battle system, the Action Input Phase is implemented by a doubly linked list where the next pointer of the current node can only be reached by completely inputting the current node. It means that reaching the current node implies that all the previous nodes must be completely inputted.


This leads to the below vital invariant for unison skill/item plugins working with the default RMMV battle system:


The Unison Invoker of an Unison Skill/Item must be the Unison Battler of that Unison Skill/Item with the smallest party member index.


Proof:



 





The only way for a battler to be the Unison Invoker of an Unison Skill/Item is to input that Unison Skill/Item.


The only way for a battler to input an Unison Skill/Item is to reserve some action slots from each of its Unison Invokees.


The only way to reserve some action slots from a battler is to mark some of that battler's empty action slots to be not accessible by players.


But as all battlers with party member indexes smaller than the would-be Unison Invoker must have no empty action slots, that Unison Invoker wouldn't be able to reserve any action slot from any of those battlers that would be the Unison Invokees.


It means any Unison Skill/Items needing any Unison Battler with party member index smaller than the current inputable actor must be not inputable.


Therefore the Unison Invoker can only have inputted Unison Skill/Items with all Unison Invokees whose party member indexes are all greater than that of the Unison Invoker.



This invariant further leads to another important invariant:


The action slot mechanics implementations only need to handle inputable actors whose party member indexes aren't less than that of the currently inputable actor.


I think its proof's so crystal clear and obvious that I don't need to show it here



On a side note: There's yet another invariant, albeit relatively trivial: The actor with the smallest party member index will never be an Unison Invokee for any Unison Skills/Items.








Action Usability Changes

As Game_BattlerBase.prototype.canUse implements the action usability checks, the action usability changes should be implemented there(DoubleX RMMV Unison Item Default v100e):



 









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 || item.meta.unisonItemActors.length <= 0) {
return GBB.canUse.apply(this, arguments);
} else if (item.meta.unisonItemActors.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 inBattle = $gameParty.inBattle(), mems = $gameParty.aliveMembers();
var actor, actorIds = skill.meta.unisonItemActors;
// Checks if all needed actors can use the skill and have empty actions
for (var index = 0, length = actorIds.length; index < length; index++) {
if (actorIds[index] === this.actorId()) { continue; }
actor = mems.filter(function(mem) {
return mem.actorId() === actorIds[index];
})[0];
if (!actor || !actor.meetsSkillConditions(skill)) { return false; }
if (actor.skills().every(function(s) { return s !== skill; })) {
return false;
}
if (inBattle && !GBB.hasInputableActs.call(actor)) { return false; }
}
//
return true;
}; // GBB.canUseUnisonSkill

GBB.hasInputableActs = function(skill) { // v1.00e+
var acts = this._actions.length - this._unisonItemNumInputs;
return acts > this._actions.filter(function(act) { return act.item(); });
}; // GBB.hasInputableActs

GBB.canUseUnisonItem = function(item) {
if (!this.meetsItemConditions(item)) { return false; }
var inBattle = $gameParty.inBattle(), 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; }
actor = mems.filter(function(mem) {
return mem.actorId() === actorIds[index];
})[0];
if (!actor || inBattle && !actor.canInput()) { return false; }
}
return true;
}; // GBB.canUseUnisonItem



For an Unison Skill/Item to be usable by the currently inputable actor:


1. The currently inputable actor must be an Unison Battler of the Unison Skill/Item


2. The currently inputable actor must pass the ordinary skill/item usability checks for the Unison Skill/Item


3. All the other Unison Battlers must be alive battlers passing the ordinary skill/item usability checks for the Unison Skill/Item(needing them to have learnt the skill is just an additional requirement of DoubleX RMMV Unison Item Default v100e but not necessary for all unison skill/item plugins)


4. All the other Unison Battlers must have enough empty action slots(1 in this case) to be reserved by the Unison Skill/Item(using GBB.hasInputableActs instead of Game_BattlerBase.prototype.canInput for skills is just to play safe as using the latter should already suffice)








Action Input Changes

There are 2 commands to consider - Next Command and Prior Command, and 4 types of action slots to consider: Ordinary Action Slots, Unison Action Slots, Empty Action Slots and Reserved Action Slots.


An Ordinary Action Slot is an action slot storing an ordinary skill/item.


An Unison Action Slot is an action slot storing an Unison Skill/Item.


An Empty Action Slot is an action slot storing no skills/items.


A Reserved Action Slot is an Empty Action Slot not accessible by players due to being reserved by an Unison Skill/Item.


Combining, there are 10 cases to consider:



 





1. Triggering Next Command right after inputting an Ordinary Action Slot


    No action input changes need to take place


    - It's because no other action slots will be affected in this case


2. Triggering Next Command right after inputting an Unison Action Slot


    Some Empty Action Slots(1 in this case) of each Unison Invokee becomes Reserved Action Slots linked to this Unison Action Slot


    - It's because each Unison Invokee needs to pay the action slot for the Unison Skill/Item


3. Reaching an Empty Action Slot right after triggering Next Command


    No action input changes need to take place


    - It's because no other action slots will be affected in this case and an Empty Action Slot's accessible by players


4. Reaching an Reserved Action Slot right after triggering Next Command


    Next Command should be kept triggered until an Empty Action Slot or the tail sentinel node(Turn Start) of the doubly linked list's reached


    - It's because a Reserved Action Slot's not accessible by players


5. Triggering Prior Command right after canceling an Ordinary Action Slot


    Change that Ordinary Action Slot to an Empty Action Slot


    - It's because not doing so can lead to an Unison Skill/Item previously inputable by the currently inputable actor to become not inputable by that actor due to some Unison Invokees having no Empty Action Slots even after all their action inputs are cancelled


6. Triggering Prior Command right after canceling an Unison Action Slot


    Change that Unison Action Slot to an Empty Action Slot


    - It's because not doing so can lead to an Unison Skill/Item previously inputable by the currently inputable actor to become not inputable by that actor due to some Unison Invokees having no Empty Action Slots even after all their action inputs are cancelled


7. Triggering Prior Command right after canceling an Empty Action Slot


    No action input changes need to take place


    - It's because no other action slots will be affected in this case and this Empty Action Slot can already be reserved by some Unison Action Slots


8. Reaching an Ordinary Action Slot right after triggering Prior Command


    No action input changes need to take place


    - It's because no other action slots will be affected in this case and an Ordinary Action Slot's accessible by players


9. Reaching an Unison Action Slot right after triggering Prior Command


    Change all Reserved Action Slots linked to this Unison Action Slot to Empty Action Slots and then clear all those linkages


    - It's because not doing so can lead to Unison Skill/Item previously inputable by the currently inputable actor to become not inputable by that actor due to some Unison Invokees having no Empty Action Slots but only Reserved Action Slots


10. Reaching an Reserved Action Slot right after triggering Prior Command


      Prior Command should be kept triggered until an Empty Action Slot or the head sentinel node(party command window) of the doubly linked list's reached


      - It's because a Reserved Action Slot's not accessible by players


To sum up, case 2, 4, 5, 6, 9, 10 need to be handled by unison skills/items plugins working with the default RMMV battle system.



The below algorithm can handle all the aforementioned 6 cases that ened to be handled(DoubleX RMMV Unison Item Default v100e):

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


Code:
    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
Code:
    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



Note that all Reserved Action Slots of each actor are placed by the bottom of that actor's Action Slot Queue, as illustrated in this flowchart:




Let's confirm how each of the aforementioned 6 cases are handled:

2. Triggering Next Command right after inputting an Unison Action Slot


    Some Empty Action Slots(1 in this case) of each Unison Invokee becomes Reserved Action Slots linked to this Unison Action Slot



 





It's done by extending BattleManager.selectNextCommand to call BM.addUnisonActors right before calling the original BattleManager.selectNextCommand(otherwise the currently inputable actor will be changed).


This stores the linkages between this Unison Action Slot and all its Reserved Action Slots of all Unison Invokees:



 











BM.unisonActors[[actor.index(), actor.actionInputIndex]] = actorIds;



This actually reserves some action slots(1 in this case) from each Unison Invokee, by converting the needed amount(1 in this case) of Empty Action Slots into Reserved Action Slots for each Unison Invokee:

actorIds.forEach(function(actorId) {
$gameActors.actor(actorId).unisonItemNumInputs += 1;
});



It's because of this line in the extended Game_BattlerBase.prototype.canInput:

return this._unisonItemNumInputs < this._actions.length;



In short, Game_Battler.prototype._unisonItemNumInputs marks the number of Reserved Action Slots of the battler, so a battler can only be inputable if that battler has non Reserved Action Slots.






4. Reaching an Reserved Action Slot right after triggering Next Command


    Next Command should be kept triggered until an Empty Action Slot or the tail sentinel node(Turn Start) of the doubly linked list's reached

It's done by the below part of the extension of Game_Actor.prototype.selectNextCommand to make it return false when the actor's action input index reaches the last non Reserved Action Slot:



 











// 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;
}
//



Recall that BattleManager.selectNextCommand will try to find a next inputable actor when Game_Actor.prototype.selectNextCommand of the current one returns false.






5. Triggering Prior Command right after canceling an Ordinary Action Slot


    Change that Ordinary Action Slot to an Empty Action Slot

It's done by this part in the exteneded BattleManager.selectPriorCommand:



 











// Added to ensure this cancelled action can be reserved for unison ones
var act = this.actor().inputtingAction();
if (act) { act.clear(); }
//



The key is to place this part right before calling the original BattleManager.selectPriorCommand, otherwise the current node of the doubly linked list won't be that Ordinary Action Slot.






6. Triggering Prior Command right after canceling an Unison Action Slot


    Change that Unison Action Slot to an Empty Action Slot


    - Its implementation's exactly the same as that of case 5.


9. Reaching an Unison Action Slot right after triggering Prior Command


    Change all Reserved Action Slots linked to this Unison Action Slot to Empty Action Slots and then clear all those linkages

It's done by extending BattleManager.selectPriorCommand to call BM.eraseUnisonActors right after calling the original BattleManager.selectPriorCommand(otherwise the action slot of the last node will be pointed to instead).


This clears the linkages between this Unison Action Slot and all its Reserved Action Slots of all Unison Invokees:



 











BM.unisonActors[[actor.index(), actor.actionInputIndex]] = null;



This actually reverts all Reserved Action Slots(1 in this case) previously linked to this Unison Action Slot back to Empty Action Slots from each Unison Invokee:

actorIds.forEach(function(actorId) {
$gameActors.actor(actorId).unisonItemNumInputs -= 1;
});



Check the implementation of case 2 to see how it works.


On a side note: It's 100% safe to clear those linkages right now, as reaching the next action slots must be done via Next Command, which can only be reached by completely inputting the current node of the doubly linked list, which will setup new linkages to newly Reserved Action Slots if the newly inputted action's an Unison Skill/Item.






10. Reaching an Reserved Action Slot right after triggering Prior Command


      Prior Command should be kept triggered until an Empty Action Slot or the head sentinel node(party command window) of the doubly linked list's reached

Its implementation's similar to that in case 4, except that e can make use of this nontrivial invariant:


Reaching an Reserved Action Slot right after triggering Prior Command implies that the currently inputable actor becomes the prior inputable actor.


It's because if that could be not the case, it'd mean a non Reserved Action Slot could be placed behind a Reserved Action Slot in the same Action Slot Queue, which is simply impossible here.


This nontrivial invariant will further lead to these 2 subcases:


a. The prior actor has no non Reserved Action Slots


    In this case, Game_BattlerBase.prototype.canInput will return false(check the implementation of case 2 for details), meaning the this prior actor will be skipped and the subsequent prior actor will be examined instead. This repeats until a prior inputable actor found or the head sentinel node(party command window) of the doubly linked list's reached.


b. The prior actor has non Reserved Action Slots


    In this case, the non Reserved Action Slot that's just in front of the most up front Reserved Action Slot will become the current node of the doubly linked list. It's because Prior Command will never lead to that prior actor before Next Command being triggered by that prior actor and the action input index of that prior actor will always be the number of non Reserved Action Slots - 1 after Next Command's triggered by that prior actor, meaning that the action input index of that prior actor will always be the number of non Reserved Action Slots - 1 after that prior actor's selected due to Prior Command.









On a side note: Extending BattleManager.startTurn to call BM.clearUnisonActors is to ensure all Unison Skills/Items will pass the Game_Action.prototype.isValid() check which is one right before executing those skills/items. It's because the Action Slot Queue for all battlers will become empty upon Turn Start, meaning that an actor can only be inputable, which is a part of the Unison Skills/Items usability check, which is a part of the action validity check, if Game_Battler.prototype._unisonItemNumInputs is negative.
 
Last edited by a moderator:

DoubleX

Just a nameless weakling
Veteran
Joined
Jan 2, 2014
Messages
1,787
Reaction score
939
First Language
Chinese
Primarily Uses
N/A
Let's talk about how to implement the action slot mechanisms for unison skill/item plugins working with Yanfly Engine Plugins - Battle System - Charge Turn Battle. For now, I'll focus on Synchronous Unison Skills/Items used by non autobattle actors.


You're assumed to have:


- Solid understanding on the implementations of Yanfly Engine Plugins - Battle System - Charge Turn Battle and DoubleX RMMV Unison Item Default(You're highly encouraged and recommended to read the last reply before going on)


- Decent battle related plugin development proficiency(experienced plugin developer having written dozens of decent battle related plugins with decent code qualities)


Let's check this video again before we start:










Battle modification requirements

Action Execution Changes








1. As only the Unison Invoker will execute the Unison Skill/Item, all the Unison Invokees only need to pay the Unison Skill/Item costs after executing that Unison Skill/Item. The implementation of this is already covered in the 1st post in this topic.


2. As Yanfly Engine Plugins - Battle System - Charge Turn Battle is based on Yanfly Engine Plugins - Battle Engine Core, which doesn't show who's executing the actions in the log window, no changes need to be made for executing Unison Skills/Items.


Action Usability Changes

1. As all Unison Battlers need to be able to use the Unison Skill/Item while only the Unison Invoker actually uses it, the action usability check of the Unison Invoker upon both inputting and executing that Unison Skill/Item needs to check all Unison Battlers' usability of that Unison Skill/Item.


Action Input Changes

1. Right after an Unison Invoker finished inputting the Unison Skill/Item, all Unison Invokees of that Unison Skill/Item needs to reserve an action slot for that Unison Skill/Item.


2. As an actor will immediately become not inputable upon finishing inputting the 1st action slot in Yanfly Engine Plugins - Battle System - Charge Turn Battle, there's no need to handle navigating from/to the next/prior action slots.


3. As only 1 actor can be inputable for the exact same frame in Yanfly Engine Plugins - Battle System - Charge Turn Battle, no Unison Invokee will be inputable nor able to use the Unison Skill/Item inputted by the Unison Invoker at the moment of inputting that skill/item.





Action Charging Changes

For Unison Skills/Items needing charging:




1. Right after an Unison Invoker finished inputting the Unison Skill/Item, all Unison Battlers will immediately start to charge that skill/item.


2. As long as all Unison Battlers are still charging the Unison Skill/Item, their charging value(as seen by the relative positioning of battlers in the Action Order Queue) must always be almost the same(while that of the Unison Invoker should be slightly larger to ensure that battler to be always placed in front of all Unison Invokees to simplify the action execution mechanisms)


3. Right after the Unison Invoker has executed the Unison Skill/Item, all Unison Invokees should be placed right behind the Unison Invoker, with the the relative positioning of all Unison Battlers in the Action Order Queue preserved









Action Input Mechanisms Resolution

Apparent Conflicts








As stated by the 3rd point in Action Input Changes, it seems that no Unison Skill/Item will ever be inputable in Yanfly Engine Plugins - Battle System - Charge Turn Battle, meaning that Synchronous Unison Skill/Item doesn't appear to work with that plugin.


Let's go back to the very definition of Unison Skills/Items - An Unison Skill/Item is a skill/item needing more than 1 battlers to use it together.


Then recite the very definition of Synchronous Unison Skills/Items - A Synchronous Unison Skill/Item is an Unison Skill/Item needing all Unison Battlers to have enough empty action slots for it to be inputable.


And compare that with that of Asynchronous Unison Skills/Items - An Asynchronous Unison Skill/Item is an Unison Skill/Item needing any Unison Battlers to have enough empty action slots for it to be inputable, and all Unison Battlers to have enough empty action slots for it to be executed.


As it's now 100% clear and obvious that it's just outright impossible for all Unison Battlers to have enough empty action slots in Yanfly Engine Plugins - Battle System - Charge Turn Battle, the definition of Synchronous Unison Skill/Item can't be directly used there without any tweaks.


Instead, let's think of what that definition wants to achieve in Yanfly Engine Plugins - Battle System - Charge Turn Battle. This leads to the next section - Defining Next To Each Other.


Defining Next To Each Other

Let's think about how the Action Order Queue of Yanfly Engine Plugins - Battle System - Charge Turn Battle works:


1. Only the battler at the 1st position of the Action Order Queue is inputable.


2. Right after that battler has completely inputted an action, that battler will either immediately execute it and then be placed at the back of the queue(The exact position's determined by that action's speed and the speed of all battlers), or be placed at the back of the queue(The exact position's determined by that action's charge rate and the speed of all battlers) and then execute it when that battler's shifted to the 1st position of the Action Order Queue again.


These imply that:


- Right after the battler at the 1st position of the Action Order Queue has completely inputted an action, the battler at the 2nd position of the Action Order Queue will become inptuable(unless the former battler has inputted an instant action or the latter battler's much slower than the former).


- If the former battler has inputted an Asynchronous Unison Skill/Item needing the latter battler as the Unison Invokee, then the latter battler can immediately become ready to execute that Unison Skill/Item(Its details will be covered in an upcoming reply). This effectively behaves like a Synchronous Unison Skill/Item, which is actually a special case of an Asynchronous Unison Skill/Item.


Such cases can be defined as Next to Each Other(DoubleX RMMV Unison Item YEP_X_BattleSysCTB):








* Action Order Queue -
* Suppose an unison skill/item needs actors a1 and a2.
* The below definition will be used:
* 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


In short, when all Unison Battlers are Next To Each Other, an Asynchronous Unison Skill/Item can behave like a Synchronous Unison Skill/Item, meaning that the latter's possible in such cases.


In other words, in Yanfly Engine Plugins - Battle System - Charge Turn Battle, a Synchronous Unison Skill/Item is an Unison Skill/Item needing all Unison Battlers to be Next To Each Other.









Action Slot Mechanism Implementations

First and foremost, Yanfly Engine Plugins - Battle System - Charge Turn Battle can be enabled and disabled on the fly, so any unison skill/item plugin working with that plugin must also work with the default RMMV battle system. That's why DoubleX RMMV Unison Item YEP_X_BattleSysCTB, which is supposed to work with Yanfly Engine Plugins - Battle System - Charge Turn Battle, needs DoubleX RMMV Unison Item Default, which is supposed to work with the default RMMV battle system.


Action Execution Changes








BattleManager.actionCastAnimation is rewritten to handle the Unison Skill/Item animations as well(DoubleX RMMV Unison Item YEP_X_BattleSysCTB v100a):








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





Action Usability Changes

As GBB.canUseUnisonSkill and GBB.canUseUnisonItem implements the action usability checks for DoubleX RMMV Unison Item Default,, the action usability changes should be implemented there(DoubleX RMMV Unison Item YEP_X_BattleSysCTB v100a):








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;
for (var index = 0, length = actorIds.length; index < length; index++) {
if (actorIds[index] === this.actorId()) { continue; }
actor = mems.filter(function(mem) {
return mem.actorId() === actorIds[index];
})[0];
if (!actor || !actor.meetsSkillConditions(skill)) { return false; }
}
if (!$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; }
return BMCTB.isUnisonTurnOrder.call(BattleManager, this, actorIds);
//
}; // GBB.canUseUnisonItem


For an Unison Skill/Item to be usable by the currently inputable actor:


1. The currently inputable actor must be an Unison Battler of the Unison Skill/Item


2. The currently inputable actor must pass the ordinary skill/item usability checks for the Unison Skill/Item


3. All the other Unison Battlers must be alive battlers passing the ordinary skill/item usability checks for the Unison Skill/Item(needing them to have learnt the skill is just an additional requirement of DoubleX RMMV Unison Item Default v100e but not necessary for all unison skill/item plugins)


4. All Unison Battlers must be Next To Each Other(Check Implementing Next To Each Other for details)





Implementing Next To Each Other

BMCTB.isUnisonTurnOrder checks if all Unison Battlers are next to each other(DoubleX RMMV Unison Item YEP_X_BattleSysCTB v100a):








/*------------------------------------------------------------------------
* 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


It basically scans the Action Order Queue from its 2nd position to its last position.


It returns false if a battler not being an Unison Invokee's found before all Unison Invokees are collected.


It returns true if all Unison Invokees are collected before a battler not being an Unison Invokee's found.


Note that it's meaningless, pointless and useless to scan for the Unison Invoker, because:


- At the moment of inputting the Unison Skill/Item, the Unison Invoker must be at the 1st position of the Action Order Queue.


- At the moment of showing the predicted Action Order Queue changes due to inputting the Unison Skill/Item by the Unison Invoker, the Unison Invoker is still at the 1st position of the Action Order Queue from the players' perspective, even though it's at the predicated position of the Action Order Queue from the implementation's perspective(So checking the Unison Invoker here as well will indeed significantly complicate the algorithm).


- At the moment of checking the validity of the Unison Skill/Item, the Unison Invoker will always be just in front of all Unison Invokees(Its details will be covered in Implementing Unison Skill/Item Charging).





Action Input Changes

Game_BattlerBase.prototype.canInput is extended for cases disabling Yanfly Engine Plugins - Battle System - Charge Turn Battle on the fly(DoubleX RMMV Unison Item YEP_X_BattleSysCTB v100a):








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


And so does Game_Actor.prototype.selectNextCommand(DoubleX RMMV Unison Item YEP_X_BattleSysCTB v100a):

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


It's because Unison Skills/Items doesn't need to reserve any action slot from any Unison Invokee here.





Action Charging Changes

Let's cite how DoubleX RMMV Unison Item YEP_X_BattleSysCTB v100a will handle the Unison Skill/Item charge rate first:








* 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




BattleManager.selectNextCommand is extended to initiate the charging of the Unison Skill/Item by all Unison Battlers(DoubleX RMMV Unison Item YEP_X_BattleSysCTB v100a):

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


Note that it's also compatible with the default RMMV battle system, by making use of DoubleX RMMV Unison Item Default.


BMCTB.setupCTBCharge is added to implement the aforementioned charging(DoubleX RMMV Unison Item YEP_X_BattleSysCTB v100a):

/*------------------------------------------------------------------------
* 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";
BMCTB.callUnisonActors.call(this, this._subject, act, fun);
}; // BMCTB.setupCTBCharge


Where GBBCTB.markUnisonActors is this(DoubleX RMMV Unison Item YEP_X_BattleSysCTB v100a):

GBBCTB.markUnisonActors = function() {
var item = this.currentAction().item();
if (item) { this._unisonItemActors = item.meta.unisonItemActors; }
}; // GBBCTB.markUnisonActors


And BMCTB.callUnisonActors is this(DoubleX RMMV Unison Item YEP_X_BattleSysCTB v100a):

/* invoker: The unison invoker
* act: The unison action
* func: The battler function to be called by all unison actors
*/
/*------------------------------------------------------------------------
* Asks each unison actor of act to call its battler function func
*------------------------------------------------------------------------*/
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


Where Game_Battler.prototype.setupUnisonCTBCharge does the real job(DoubleX RMMV Unison Item YEP_X_BattleSysCTB v100a):

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');
}; // Game_Battler.prototype.setupUnisonCTBCharge


And GACTB.setUnisonAct is used to make the CTB implementation think that each Unison Invokee has a real action to execute, although none of them will actually be executed(DoubleX RMMV Unison Item YEP_X_BattleSysCTB v100a):

/*------------------------------------------------------------------------
* 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




Game_Party.prototype.updateTick is added to synchronize the charging value of all Unison Battlers while ensuring the Unison Invoker will always be just in front of all Unison Invokees(DoubleX RMMV Unison Item YEP_X_BattleSysCTB v100a):

/*------------------------------------------------------------------------
* Ensures the charging value is the same for all unison actors
*------------------------------------------------------------------------*/
Game_Party.prototype.updateTick = function() { // New
Game_Unit.prototype.updateTick.call(this);
var actors, item, val, types = ["Charge", "Speed", "TickValue"];
var rule = $gameSystem.unisonItem.unisonFunctionRule;
this.aliveMembers().forEach(function(mem) {
if (mem.unisonItemActors.length <= 1) { return; }
actors = mem.unisonItemActors.map(function(actorId) {
return $gameActors.actor(actorId);
});
if (!actors.every(function(actor) {
return actor.isCTBCharging();
})) { return; }
types.forEach(function(type) {
val = UI.RULES.call(mem, rule, actors.map(function(actor) {
return actor["ctb" + type]();
}));
actors.forEach(function(actor) {
// Ensures the unison invoker will always be the fastest
if (actor === mem) {
val += Number.EPSILON * mem.ctbChargeDestination();
}
//
actor["setCTB" + type](val);
});
});
});
}; // Game_Party.prototype.updateTick


Note that:


1. There are 3 values to synchronize - ctbCharge, ctbSpeed, ctbTickValue as their getters, and setCTBCharge, setCTBSpeed, setCTBTickValue as setters.


2. Number.EPSILON * mem.ctbChargeDestination is the difference that's large enough to be detectable by the plugin, yet small enough to make it almost impossible for any battler to be placed between any Unison Battler in order to ensure all Unison Battlers are kept Next To Each Other.


3. Without the 2nd point, an Unison Invoker, who has a real action that are not supposed to be executed, might be placed in front of all other Unison Battlers and indeed execute that real action, or be regarded as having an invalid action and then being placed at some other positions of the Action Order Queue, thus breaking the Next To Each Other property.


BattleManager.endCTBAction is rewritten to reset the position of all Unison Invokees as well(DoubleX RMMV Unison Item YEP_X_BattleSysCTB v100a):

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();
}
};


Where BMCTB.endCTBAct is this(DoubleX RMMV Unison Item YEP_X_BattleSysCTB v100a):

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


So all Unison Battlers will call Game_Battler.prototype.endTurnAllCTB together.


Game_Battler.prototype.onAllActionsEnd and Game_Battler.prototype.resetAllCTB are extended to mark the end of the Unison Skill/Item execution(DoubleX RMMV Unison Item YEP_X_BattleSysCTB v100a):

Code:
    GBCTB.onAllActionsEnd = Game_Battler.prototype.onAllActionsEnd;
    Game_Battler.prototype.onAllActionsEnd = function() {
        GBCTB.onAllActionsEnd.apply(this, arguments);
        this._unisonItemActors = []; // Added
    }; // Game_Battler.prototype.onAllActionsEnd

    GBCTB.resetAllCTB = Game_Battler.prototype.resetAllCTB;
    Game_Battler.prototype.resetAllCTB = function() {
        GBCTB.resetAllCTB.apply(this, arguments);
        this._unisonItemActors = []; // Added
    }; // Game_Battler.prototype.resetAllCTB
 

DoubleX

Just a nameless weakling
Veteran
Joined
Jan 2, 2014
Messages
1,787
Reaction score
939
First Language
Chinese
Primarily Uses
N/A
Let's talk about how to implement the action slot mechanisms for unison skill/item plugins working with Yanfly Engine Plugins - Battle System - Charge Turn Battle. For now, I'll focus on Asynchronous Unison Skills/Items used by non autobattle actors.


You're assumed to have:


- Solid understanding on the implementations of Yanfly Engine Plugins - Battle System - Charge Turn Battle and DoubleX RMMV Unison Item Default(You're highly encouraged and recommended to read the last reply before going on)


- Decent battle related plugin development proficiency(experienced plugin developer having written dozens of decent battle related plugins with decent code qualities)


Let's check this video again before we start:










Battle modification requirements

Action Execution Changes



Spoiler



1. As only the Unison Invoker will execute the Unison Skill/Item, all the Unison Invokees only need to pay the Unison Skill/Item costs after executing that Unison Skill/Item. The implementation of this is already covered in the 1st post in this topic.


2. As Yanfly Engine Plugins - Battle System - Charge Turn Battle is based on Yanfly Engine Plugins - Battle Engine Core, which doesn't show who's executing the actions in the log window, no changes need to be made for executing Unison Skills/Items.

Action Usability Changes

1. As Asynchronous Unison Skills/Items never reserves any action slot from any of its Unison Invokees, the action usability check can use the default one, except that the one inputting it must be its Unison Battler.


On a side note: This plugin also let you check if all Unison Battlers have learned the Unison Skill/Item, but it's not a must for all Asynchronous Unison Skills/Items.

Action Input Changes

1. Right after an Unison Battler finished inputting the Unison Skill/Item, that Unison Battler will enter the Asynchronous Unison Skill/Item Queue(A queue storing Unison Battlers having inputted the Asynchronous Unison Skill/Item).


2. Right after that Unison Battler becomes unable to use the Unison Skill/Item, that Unison Battler will leave the Asynchronous Unison Skill/Item Queue.


3. When all Unison Battlers of the Unison Skill/Item are in the Asynchronous Unison Skill/Item Queue, the Unison Skill/Item can begin to be charged.


4. The 1st Unison Battler in the Asynchronous Unison Skill/Item Queue is always the Unison Invoker of the Unison Skill/Item.

Action Charging Changes

For Unison Skills/Items needing charging:




1. Right after all Unison Invokers finished inputting the Unison Skill/Item, all Unison Battlers will immediately start to charge that skill/item.


2. As long as all Unison Battlers are still charging the Unison Skill/Item, their charging value(as seen by the relative positioning of battlers in the Action Order Queue) must always be almost the same(while that of the Unison Invoker should be slightly larger to ensure that battler to be always placed in front of all Unison Invokees to simplify the action execution mechanisms)


3. Right after the Unison Invoker has executed the Unison Skill/Item, all Unison Invokees should be placed right behind the Unison Invoker, with the the relative positioning of all Unison Battlers in the Action Order Queue preserved









Action Slot Mechanism Implementations

First and foremost, Yanfly Engine Plugins - Battle System - Charge Turn Battle can be enabled and disabled on the fly, so any unison skill/item plugin working with that plugin must also work with the default RMMV battle system. That's why DoubleX RMMV Unison Item YEP_X_BattleSysCTB, which is supposed to work with Yanfly Engine Plugins - Battle System - Charge Turn Battle, needs DoubleX RMMV Unison Item Default, which is supposed to work with the default RMMV battle system.


Action Execution Changes



Spoiler



The exact same code as those for Synchronous Unison Skills/Items can be used, as Asynchronous Unison Skills/Items behaves exactly the same as Synchronous Unison Skills/Items when it comes to action execution.

Action Usability Changes

As GBB.canUseUnisonSkill and GBB.canUseUnisonItem implements the action usability checks for DoubleX RMMV Unison Item Default, the action usability changes should be implemented there(DoubleX RMMV Unison Item YEP_X_BattleSysCTB v100a):



Spoiler



    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

For an Unison Skill/Item to be usable by the currently inputable actor:


1. The currently inputable actor must be an Unison Battler of the Unison Skill/Item


2. The currently inputable actor must pass the ordinary skill/item usability checks for the Unison Skill/Item


On a side note: This plugin has 1 more requirement - All the other Unison Battlers must be alive battlers. It's not a must for Asynchronous Unison Skills/Items, but I feel/think that it's a reasonable balance between the risk of infinite wait for Unison Battlers in the Asynchronous Unison Skill/Item Queue and the control and freedom offered by Asynchronous Unison Skills/Items.




Action Input Changes

The exact same code as those for Synchronous Unison Skills/Items can be used, as Asynchronous Unison Skills/Items never need to reserve any Unison Invokee's action slots.


On the other hand, some new codes have to be added to implement the Asynchronous Unison Skill/Item Queue.


BattleManager.setup is extended to initialize the Asynchronous Unison Skill/Item Queue container that can store a queue for each Asynchronous Unison Skill/Item(DoubleX RMMV Unison Item YEP_X_BattleSysCTB v1.00b):



Spoiler



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

BMCTB.removeAsyncUnisonBattler is added to remove an Unison Battler of an Unison Skill/Item from its Asynchronous Unison Skill/Item Queue(DoubleX RMMV Unison Item YEP_X_BattleSysCTB v1.00b):

    /*------------------------------------------------------------------------
     *    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(item) {
            index = item.indexOf(battler);
            if (index > 0) { item.splice(index, 1); }
        });
        //
    }; // BMCTB.removeAsyncUnisonActor

Note that checking if the Asynchronous Unison Skill/Item Queue container already exists is just to play safe.


It's called in GBCTB.resetUnisonItem when the battler's ATB's reset(DoubleX RMMV Unison Item YEP_X_BattleSysCTB v1.00b):

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

GBBCTB.markAsyncUnisonItemBattlers is added to add the currently inputable actor into the Asynchronous Unison Skill/Item Queue of the Asynchronous Unison Skill/Item that actor have just inputted(DoubleX RMMV Unison Item YEP_X_BattleSysCTB v1.00b):

    /*------------------------------------------------------------------------
     *    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]) {
            BattleManager.asyncUnisonItems[item] = [];
        }
        var actors = BattleManager.asyncUnisonItems[item];
        // 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

Note that it also marks that the Asynchronous Unison Skill/Item can begin to be charged once the Asynchronous Unison Skill/Item Queue has all Unison Battlers of the Asynchronous Unison Skill/Item.


Besides, some codes for Synchronous Unison Skills/Items won't be used here.


BMCTB.setupCTBCharge is updated to stop calling BMCTB.callUnisonActors for Asynchronous Unison Skills/Items(DoubleX RMMV Unison Item YEP_X_BattleSysCTB v1.00b):

    /*------------------------------------------------------------------------
     *    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




Action Charging Changes

The exact same code as those for Synchronous Unison Skills/Items can be used, as Asynchronous Unison Skills/Items behaves exactly the same as Synchronous Unison Skills/Items when it comes to charging.
 

DoubleX

Just a nameless weakling
Veteran
Joined
Jan 2, 2014
Messages
1,787
Reaction score
939
First Language
Chinese
Primarily Uses
N/A
Let's talk about how to implement the action slot mechanisms for unison skill/item plugins working with Yanfly Engine Plugins - Battle System - Active Turn Battle. For now, I'll focus on Asynchronous Unison Skills/Items used by non autobattle actors.


As the ATB in Yanfly Engine Plugins - Battle System - Active Turn Battle will always stop whenever an actor's inputable, only Asynchronous Unison Skills/Items can be implemented there, due to the fact that it's extremely unlikely for more than 1 battler to become inputable at the exact same frame.


You're assumed to have:


- Solid understanding on the implementations of Yanfly Engine Plugins - Battle System - Active Turn Battle and DoubleX RMMV Unison Item Default


- Decent battle related plugin development proficiency(experienced plugin developer having written dozens of decent battle related plugins with decent code qualities)


Let's check this video again before we start:










Battle modification requirements

Action Execution Changes



Spoiler



They're exactly the same as those for Asynchronous Unison Skills/Items in DoubleX RMMV Unison Item YEP_X_BattleSysCTB.

Action Usability Changes

They're exactly the same as those for Asynchronous Unison Skills/Items in DoubleX RMMV Unison Item YEP_X_BattleSysCTB.


The only exception is that, DoubleX RMMV Unison Item YEP_X_BattleSysATB doesn't need to handle the changes for Synchronous Unison Skills/Items as well.
Action Input Changes



They're exactly the same as those for Asynchronous Unison Skills/Items in DoubleX RMMV Unison Item YEP_X_BattleSysCTB.


The only exception is that, DoubleX RMMV Unison Item YEP_X_BattleSysATB doesn't need to handle the changes for Synchronous Unison Skills/Items as well.
Action Charging Changes



They're exactly the same as those for Asynchronous Unison Skills/Items in DoubleX RMMV Unison Item YEP_X_BattleSysCTB.





Action Slot Mechanism Implementations

First and foremost, Yanfly Engine Plugins - Battle System - Active Turn Battle can be enabled and disabled on the fly, so any unison skill/item plugin working with that plugin must also work with the default RMMV battle system. That's why DoubleX RMMV Unison Item YEP_X_BattleSysATB, which is supposed to work with Yanfly Engine Plugins - Battle System - Active Turn Battle, needs DoubleX RMMV Unison Item Default, which is supposed to work with the default RMMV battle system.


Action Execution Changes



Spoiler



The exact same code as those for Asynchronous Unison Skills/Items in DoubleX RMMV Unison Item YEP_X_BattleSysCTB can be used, as they share the exact same changes.

Action Usability Changes

The exact same code as those for Asynchronous Unison Skills/Items in DoubleX RMMV Unison Item YEP_X_BattleSysCTB can be used, as they share the exact same changes.


The only exception is that, DoubleX RMMV Unison Item YEP_X_BattleSysATB doesn't have to implement the Synchronous Unison Skills/Items case as well.

Action Input Changes

The exact same code as those for Asynchronous Unison Skills/Items in DoubleX RMMV Unison Item YEP_X_BattleSysCTB can be used, as they share the exact same changes.


The only exception is that, DoubleX RMMV Unison Item YEP_X_BattleSysATB doesn't have to implement the Synchronous Unison Skills/Items case as well.
Action Charging Changes



The exact same code as those for Asynchronous Unison Skills/Items in DoubleX RMMV Unison Item YEP_X_BattleSysCTB can be used, as they share the exact same changes.
 

Users Who Are Viewing This Thread (Users: 0, Guests: 1)

Latest Threads

Latest Profile Posts

Do you Find Tilesetting or Looking for Tilesets/Plugins more fun? Personally I like making my tileset for my Game (Cretaceous Park TM) xD
How many parameters is 'too many'??
Yay, now back in action Happy Christmas time, coming back!






Back in action to develop the indie game that has been long overdue... Final Fallacy. A game that keeps on giving! The development never ends as the developer thinks to be the smart cookie by coming back and beginning by saying... "Oh bother, this indie game has been long overdue..." How could one resist such? No-one c
So I was playing with filters and this looked interesting...

Versus the normal look...

Kind of gives a very different feel. :LZSexcite:

Forum statistics

Threads
105,854
Messages
1,017,004
Members
137,562
Latest member
tamedeathman
Top