We all know what anonymous functions are as almost all of us work with them all the time and the majority of us use them all the time.
Many of us have also heard of plugin container, which is an object containing all new functions added by the plugin, or similar concepts.
But how about using them together? DoubleX RMMv Item Triggers gives an example for this experiment:
Note that extended functions always use apply only, while new functions always use call only.
This style exhibits at least the below 3 traits:
1. Almost the whole plugin's implementation's(except declaring new classes which will be done before calling the anonymous function) wrapped by a single anonymous function
2. Every new function's wrapped by a single container - the plugin object(DoubleX_RMMV.Item_Triggers in this case)
3. Every new function declared and extended function in the anonymous function's accessible via the plugin object as the container(like DoubleX_RMMV.Item_Triggers.Scene_ItemBase.useItem.apply(sceneItemBasePrototype, arguments) for calling the extended function SIB.useItem and DoubleX_RMMV.Item_Triggers.Game_BattlerBase.execItemTriggers.call(battler, item, timing) for calling the new function GBB.execItemTriggers)
Of course this style also has at least 3 issues:
1. Using call to call a function is at least slightly less performant than directly calling it
2. It makes other plugins calling new or extended functions in mine much, much more painful(just compare DoubleX_RMMV.Item_Triggers.Scene_ItemBase.useItem.apply(this, arguments) with this.useItem() and DoubleX_RMMV.Item_Triggers.Game_BattlerBase.execItemTriggers.call(this, item, timing) with this.execItemTriggers(item, timing))
3. It doesn't allow the use of polymorphism via subtyping.
For example, without this style, I can use that trick this way(DoubleX RMMV Intercept Item):
With this style, that trick no longer works. I'll have to choose either of the below:
On a side note: It means an extra checking(whether interceptor is an actor) has to be added now, when it can be replaced by polymorphism via subtying without my new experimental setup.
What do you think about the combination of anonymous function with plugin container? Let's drop your 2 cents here :)
Many of us have also heard of plugin container, which is an object containing all new functions added by the plugin, or similar concepts.
But how about using them together? DoubleX RMMv Item Triggers gives an example for this experiment:
JavaScript:
(function(IT) {
IT.DataManager = {};
var DM = IT.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 regExp = /< *(\w+) +item +trigger *: *(\w+) *, *(\w+) *>/i;
var timing, triggers;
data.meta.itemTriggers = {};
triggers = data.meta.itemTriggers;
data.note.split(/[\r\n]+/).forEach(function(line) {
if (!line.match(regExp)) { return; }
timing = RegExp.$1;
triggers[timing] = triggers[timing] || [];
triggers[timing].push([RegExp.$2, RegExp.$3]);
});
}; // DM.loadItemNotes
IT.BattleManager = {};
var BM = IT.BattleManager;
BM.startAction = BattleManager.startAction;
BattleManager.startAction = function() {
// Added
var item = this._subject.currentAction().item();
GBB.execItemTriggers.call(this._subject, item, "preBattle");
//
BM.startAction.apply(this, arguments);
}; // BattleManager.startAction
BM.endAction = BattleManager.endAction;
BattleManager.endAction = function() {
BM.endAction.apply(this, arguments);
// Added
var item = this._action ? this._action.item() : null;
if (!item) { return; }
GBB.execItemTriggers.call(this._subject, item, "postBattle");
//
}; // BattleManager.endAction
IT.Game_BattlerBase = {};
var GBB = IT.Game_BattlerBase;
/*------------------------------------------------------------------------
* Triggers each item action when each respective condition's met
*------------------------------------------------------------------------*/
// timing: The timing of the item triggering its actions
GBB.execItemTriggers = function(item, timing) {
var triggers = item.meta.itemTriggers[timing];
if (!triggers) { return; }
// Calls each ITCX to see if its ITAX should be called as well
triggers.forEach(function(trigger) {
if (IT[trigger[0]].call(this)) { IT[trigger[1]].call(this); }
}, this);
//
}; // GBB.execItemTriggers
IT.Scene_ItemBase = {};
var SIB = IT.Scene_ItemBase;
SIB.useItem = Scene_ItemBase.prototype.useItem;
Scene_ItemBase.prototype.useItem = function() {
GBB.execItemTriggers.call(this.user(), this.item(), "preMap"); // Added
SIB.useItem.apply(this, arguments);
GBB.execItemTriggers.call(this.user(), this.item(), "postMap"); // Added
}; // Scene_ItemBase.prototype.useItem
})(DoubleX_RMMV.Item_Triggers);
This style exhibits at least the below 3 traits:
1. Almost the whole plugin's implementation's(except declaring new classes which will be done before calling the anonymous function) wrapped by a single anonymous function
2. Every new function's wrapped by a single container - the plugin object(DoubleX_RMMV.Item_Triggers in this case)
3. Every new function declared and extended function in the anonymous function's accessible via the plugin object as the container(like DoubleX_RMMV.Item_Triggers.Scene_ItemBase.useItem.apply(sceneItemBasePrototype, arguments) for calling the extended function SIB.useItem and DoubleX_RMMV.Item_Triggers.Game_BattlerBase.execItemTriggers.call(battler, item, timing) for calling the new function GBB.execItemTriggers)
Of course this style also has at least 3 issues:
1. Using call to call a function is at least slightly less performant than directly calling it
2. It makes other plugins calling new or extended functions in mine much, much more painful(just compare DoubleX_RMMV.Item_Triggers.Scene_ItemBase.useItem.apply(this, arguments) with this.useItem() and DoubleX_RMMV.Item_Triggers.Game_BattlerBase.execItemTriggers.call(this, item, timing) with this.execItemTriggers(item, timing))
3. It doesn't allow the use of polymorphism via subtyping.
For example, without this style, I can use that trick this way(DoubleX RMMV Intercept Item):
JavaScript:
BattleManager.successIntercept = function(interceptor, subject, act, item) {
// Some codes irrelevant with this issue
//
if (interceptor.canLearnInterceptItem(item)) {
// Some codes irrelevant with this issue
//
}
// Some codes irrelevant with this issue
//
}; // BattleManager.successIntercept
// item: The skill/item to be intercepted
Game_Battler.prototype.canLearnInterceptItem = function(item) {
return false;
}; // Game_Battler.prototype.canLearnInterceptItem
// item: The skill/item to be intercepted
Game_Actor.prototype.canLearnInterceptItem = function(item) {
if (!DataManager.isSkill(item)) { return false; }
if (!item.meta.learnInterceptItem) { return false; }
return this.interceptNote("learnInterceptItem");
}; // Game_Actor.prototype.canLearnInterceptItem
JavaScript:
/* interceptor: The battler intercepting the skill/item
* item: The skill/item to be intercepted
*/
II.BattleManager.successIntercept =function(interceptor, item){
// Some codes irrelevant with this issue
//
if (II.Game_Battler.canLearnInterceptItem.call(interceptor, item)) {
// Some codes irrelevant with this issue
//
}
// Some codes irrelevant with this issue
//
}; // II.BattleManager.successIntercept
// item: The skill/item to be intercepted
II.Game_Battler.canLearnInterceptItem = function(item) {
if (!this.isActor() || !DataManager.isSkill(item)) { return false; }
if (!item.meta.learnInterceptItem) { return false; }
return II.Game_Battler.interceptNote.call(this, "learnInterceptItem");
}; // II.Game_Battler.canLearnInterceptItem
JavaScript:
/* interceptor: The battler intercepting the skill/item
* item: The skill/item to be intercepted
*/
II.BattleManager.successIntercept =function(interceptor, item){
// Some codes irrelevant with this issue
//
if (interceptor.isActor()) {
if (II.Game_Actor.canLearnInterceptItem.call(interceptor, item)) {
// Some codes irrelevant with this issue
//
}
}
// Some codes irrelevant with this issue
//
}; // II.BattleManager.successIntercept
// item: The skill/item to be intercepted
II.Game_Actor.canLearnInterceptItem = function(item) {
if (!DataManager.isSkill(item)) { return false; }
if (!item.meta.learnInterceptItem) { return false; }
return II.Game_Battler.interceptNote.call(this, "learnInterceptItem");
}; // II.Game_Actor.canLearnInterceptItem
What do you think about the combination of anonymous function with plugin container? Let's drop your 2 cents here :)
Last edited: