JUMP INTO JAVASCRIPT PART 4

The teardown series continues to continue.

  • Trihan
  • 02/08/2017 03:24 PM
  • 1988 views
Salutations of greeting, enjoyers of recreational physical exertion! It's that time again.


Jump into Javascript

We'll get right back into it with a teardown of the base scene for menus. Since a lot of what we're going to cover has been present in a number of other classes, I'm going to start being more concise with terminology and skipping functions that don't do anything unique.

Scene_MenuBase

Scene_MenuBase.prototype.create = function() {
    Scene_Base.prototype.create.call(this);
    this.createBackground();
    this.updateActor();
    this.createWindowLayer();
};


After the standard call to the base create function, we call functions for creating the menu background, updating the selected actor, and creating the window layer.

Scene_MenuBase.prototype.actor = function() {
    return this._actor;
};


The actor function is a getter which simply returns the value of the scene's _actor variable. I'm going to stop referring to them as "instance variables" since the _ at the start of the name should make that obvious by now.

[NEW(ISH) CONCEPT: ENCAPSULATION]
In all honesty I probably should have done a section on this before, but it didn't really occur to me until now.

For those of you who aren't familiar with object-oriented programming, you may have noticed that a lot of the time we're calling functions which do nothing but return the value of a variable. "So why not just use the variable directly?" you might quite reasonably ask.

And there'd be nothing stopping you from doing so; using "var actor = this._actor;" instead of "var actor = this.actor();" would be just as valid and would work the same way. So why would we add this extra layer when it's technically not needed? The answer is encapsulation.

The essential gist of encapsulation is that wherever possible, external objects should have as little control over and knowledge of the internal workings of another object as possible, even if one is a child of the other. _actor is defined in Scene_MenuBase, and so Scene_MenuBase is theoretically the only class that should directly reference it. Although other classes like Scene_Skill are children of it (through Scene_ItemBase) we don't want them to look directly at _actor, so we create a function in the base class that other classes can use to get the value of the variable when needed. This means that even if later on, for whatever reason, we decided to change the name of the variable in the base class (to _hero for example) everything else outwith the base class that uses it can still call actor() and get the correct value out, so you don't have to go and hunt down every part of your code that used the value and change the name there too.


Scene_MenuBase.prototype.updateActor = function() {
    this._actor = $gameParty.menuActor();
};


updateActor sets the _actor variable to the currently-selected actor as returned by $gameParty's menuActor function.

Scene_MenuBase.prototype.createBackground = function() {
    this._backgroundSprite = new Sprite();
    this._backgroundSprite.bitmap = SceneManager.backgroundBitmap();
    this.addChild(this._backgroundSprite);
};


createBackground creates a new Sprite assigned to _backgroundSprite and sets its bitmap to the return value of SceneManager's backgroundBitmap function (which is a blurry copy of the map the player is on). Then the background sprite is added as a child of the scene.

Scene_MenuBase.prototype.setBackgroundOpacity = function(opacity) {
    this._backgroundSprite.opacity = opacity;
};


setBackgroundOpacity takes opacity as a parameter and sets the opacity property of _backgroundSprite to the passed-in value.

Scene_MenuBase.prototype.createHelpWindow = function() {
    this._helpWindow = new Window_Help();
    this.addWindow(this._helpWindow);
};


createHelpWindow creates a new instance of Window_Help assigned to _helpWindow and then adds it to the window layer.

Scene_MenuBase.prototype.nextActor = function() {
    $gameParty.makeMenuActorNext();
    this.updateActor();
    this.onActorChange();
};


nextActor shifts to the next party member via the makeMenuActorNext function of $gameParty, then calls functions that update the actor and respond to actor changes.

Scene_MenuBase.prototype.previousActor = function() {
    $gameParty.makeMenuActorPrevious();
    this.updateActor();
    this.onActorChange();
};


Same thing, but for the previous actor.

Scene_MenuBase.prototype.onActorChange = function() {
};


The base onActorChange doesn't actually do anything, but some menu scenes will overwrite it with their own versions. I think it's basically only included here as either a reminder that it exists or to prevent the game from crashing if you create a custom menu scene that allows page up/page down actor scrolling and forget to overwrite it.

Scene_Menu

Scene_Menu.prototype.create = function() {
    Scene_MenuBase.prototype.create.call(this);
    this.createCommandWindow();
    this.createGoldWindow();
    this.createStatusWindow();
};


The create function, after the base function call, creates the command window, gold window and status window.

Scene_Menu.prototype.start = function() {
    Scene_MenuBase.prototype.start.call(this);
    this._statusWindow.refresh();
};


The start function calls the base start function and then refreshes the status window.

Scene_Menu.prototype.createCommandWindow = function() {
    this._commandWindow = new Window_MenuCommand(0, 0);
    this._commandWindow.setHandler('item',      this.commandItem.bind(this));
    this._commandWindow.setHandler('skill',     this.commandPersonal.bind(this));
    this._commandWindow.setHandler('equip',     this.commandPersonal.bind(this));
    this._commandWindow.setHandler('status',    this.commandPersonal.bind(this));
    this._commandWindow.setHandler('formation', this.commandFormation.bind(this));
    this._commandWindow.setHandler('options',   this.commandOptions.bind(this));
    this._commandWindow.setHandler('save',      this.commandSave.bind(this));
    this._commandWindow.setHandler('gameEnd',   this.commandGameEnd.bind(this));
    this._commandWindow.setHandler('cancel',    this.popScene.bind(this));
    this.addWindow(this._commandWindow);
};


Finally we get a slightly more interesting function. createCommandWindow does exactly what it implies.

First, we create a new instance of Window_MenuCommand, passing in arguments of 0 and 0 for the X and Y position, and assign it to _commandWindow.

We then call the setHandler function for each of the menu options, passing in the symbols corresponding to the options and a binding of the function that will be called when that option is selected (we looked at this last time). Finally, the command window is added to the window layer.

Scene_Menu.prototype.createGoldWindow = function() {
    this._goldWindow = new Window_Gold(0, 0);
    this._goldWindow.y = Graphics.boxHeight - this._goldWindow.height;
    this.addWindow(this._goldWindow);
};


To create the gold window, we create a new instance of Window_Gold at X/Y (0, 0), then set its Y coordinate to the height of the game window minus the height of the gold window (which will place it at the bottom) and finally add it to the window layer.

Scene_Menu.prototype.createStatusWindow = function() {
    this._statusWindow = new Window_MenuStatus(this._commandWindow.width, 0);
    this.addWindow(this._statusWindow);
};


Creating the status window consists of creating a new instance of Window_MenuStatus, passing in the command window's width and 0 as the X/Y, then adding it to the window layer. Setting X to the width of the command window means that the status window will start from wherever the command window ends.

Scene_Menu.prototype.commandItem = function() {
    SceneManager.push(Scene_Item);
};


commandItem is the function that will be called when the 'item' handler is selected, and pushes Scene_Item to SceneManager.

Scene_Menu.prototype.commandPersonal = function() {
    this._statusWindow.setFormationMode(false);
    this._statusWindow.selectLast();
    this._statusWindow.activate();
    this._statusWindow.setHandler('ok',     this.onPersonalOk.bind(this));
    this._statusWindow.setHandler('cancel', this.onPersonalCancel.bind(this));
};


commandPersonal is the function associated with the handlers for 'skill', 'equip' and 'status'; basically the menu options which require selecting an actor.

We set the status window's formation mode to false (otherwise it'll think we're rearranging party members instead of selecting one), select the most recently highlighted party member, activate the status window, then call setHandler for the symbols 'ok' and 'cancel', binding them to the onPersonalOk and onPersonalCancel functions respectively.

Scene_Menu.prototype.commandFormation = function() {
    this._statusWindow.setFormationMode(true);
    this._statusWindow.selectLast();
    this._statusWindow.activate();
    this._statusWindow.setHandler('ok',     this.onFormationOk.bind(this));
    this._statusWindow.setHandler('cancel', this.onFormationCancel.bind(this));
};


commandFormation is the function associated with the handler for 'formation'. We set formation mode to true, so the status window will know we're moving actors around instead of selecting one. Then we select the most recently highlighted party member, activate the status window, and bind onFormationOk and onFormationCancel to the 'ok' and 'cancel' symbol handlers.

Scene_Menu.prototype.commandOptions = function() {
    SceneManager.push(Scene_Options);
};


commandOptions is the function associated with the handler for 'options' and simply pushes Scene_Options to SceneManager.

Scene_Menu.prototype.commandSave = function() {
    SceneManager.push(Scene_Save);
};


Same as before but for save rather than options.

Scene_Menu.prototype.commandGameEnd = function() {
    SceneManager.push(Scene_GameEnd);
};


Same as before but for end game.

Scene_Menu.prototype.onPersonalOk = function() {
    switch (this._commandWindow.currentSymbol()) {
    case 'skill':
        SceneManager.push(Scene_Skill);
        break;
    case 'equip':
        SceneManager.push(Scene_Equip);
        break;
    case 'status':
        SceneManager.push(Scene_Status);
        break;
    }
};


onPersonalOk is the function that is bound to the 'ok' handler of commandPersonal, so it will be called when the player confirms the selection of an actor when one of the associated menu options is selected.

We have a switch statement for the current symbol of the command window; if it's 'skill', we push Scene_Skill to SceneManager. If it's 'equip', we push Scene_Equip. And finally, if it's 'status', we push Scene_Status. This calls the relevant scene depending on the selected menu option.

Scene_Menu.prototype.onPersonalCancel = function() {
    this._statusWindow.deselect();
    this._commandWindow.activate();
};


onPersonalCancel is the function that is bound to the 'cancel' handler of commandPersonal, so it will be called when the player presses the cancel input while an actor is highlighted. It deselects the status window and reactivates the command window.

Scene_Menu.prototype.onFormationOk = function() {
    var index = this._statusWindow.index();
    var actor = $gameParty.members()[index];
    var pendingIndex = this._statusWindow.pendingIndex();
    if (pendingIndex >= 0) {
        $gameParty.swapOrder(index, pendingIndex);
        this._statusWindow.setPendingIndex(-1);
        this._statusWindow.redrawItem(index);
    } else {
        this._statusWindow.setPendingIndex(index);
    }
    this._statusWindow.activate();
};


onFormationOk is the function that is bound to the 'ok' handler of commandFormation, so it will be called when the player confirms the selection of an actor while the 'formation' command is selected.

We set a local variable called index to the index of the status window, and one called actor to the party member occupying that index. Another variable called pendingIndex is set to the pending index of the status window (the actor waiting to be swapped).

If pending index is greater than or equal to 0, we swap the order of the party members occupying index and pending index (so if index is 2 and pendingIndex is 3, for example, party members 3 and 4 will swap positions). Following this, we set the pending index to -1 and redraw the item at index, which refreshes the display of the actor at that position (setPendingIndex already does this for the swap target, so we only need to call redrawItem once). If the pending index is not greater than or equal to 0 (meaning the first actor hasn't been chosen yet) we set pending index to index.

Finally, we activate the status window.

Basically, this is saying "If I've selected an actor for the first time, make that actor's index the pending index. If I select another one and already have a pending index, swap those actors around."

Scene_Menu.prototype.onFormationCancel = function() {
    if (this._statusWindow.pendingIndex() >= 0) {
        this._statusWindow.setPendingIndex(-1);
        this._statusWindow.activate();
    } else {
        this._statusWindow.deselect();
        this._commandWindow.activate();
    }
};


onFormationCancel is the function that is bound to the 'cancel' handler of commandFormation, so it will be called when the player presses the cancel input while the 'formation' command is selected.

If the status window's pending index is greater than or equal to 0 (we've already chosen one actor for the formation swap), we set pending index to -1 and activate the status window. Otherwise, we set the selected index of the status window to -1 (so no actor is selected) and activate the command window.

Scene_ItemBase

Despite its name, Scene_ItemBase actually acts as a base class for both Scene_Item and Scene_Skill. Technically, skills are treated as items just like the useable inventory items are.

Scene_ItemBase.prototype.createActorWindow = function() {
    this._actorWindow = new Window_MenuActor();
    this._actorWindow.setHandler('ok',     this.onActorOk.bind(this));
    this._actorWindow.setHandler('cancel', this.onActorCancel.bind(this));
    this.addWindow(this._actorWindow);
};


createActorWindow creates the subwindow in the item/skill menu from which you choose actors to use items/skills on. We create a new instance of Window_MenuActor and assign it to _actorWindow, then bind the functions onActorOk and onActorCancel to its 'ok' and 'cancel' handlers. Finally, we add the actor window to the window layer.

Scene_ItemBase.prototype.item = function() {
    return this._itemWindow.item();
};


The item function gets the currently selected item by returning the result of calling the item window's item function. Item.

Scene_ItemBase.prototype.user = function() {
    return null;
};


As this is a base class for the item and skill scenes, the base user function just returns null. The inherited classes will overwrite this with their own functionality.

Scene_ItemBase.prototype.isCursorLeft = function() {
    return this._itemWindow.index() % 2 === 0;
};


isCursorLeft determines whether the cursor is on the left or right column of the 2-column item list; returns true if the item window's index divides evenly by 2, or false otherwise.

Scene_ItemBase.prototype.showSubWindow = function(window) {
    window.x = this.isCursorLeft() ? Graphics.boxWidth - window.width : 0;
    window.show();
    window.activate();
};


showSubWindow takes one parameter, window. The passed-in window's x is set to the width of the game window minus the width of the passed-in window if the cursor is on the left, or 0 otherwise (this will open the subwindow on the left if the cursor is on the right, and on the far right if the cursor is on the left, to avoid overlap). Then we show and activate the passed-in window.

Scene_ItemBase.prototype.hideSubWindow = function(window) {
    window.hide();
    window.deactivate();
    this.activateItemWindow();
};


hideSubWindow takes one parameter, window. The passed-in window is hidden and deactivated, and then the item window is activated.

Scene_ItemBase.prototype.onActorOk = function() {
    if (this.canUse()) {
        this.useItem();
    } else {
        SoundManager.playBuzzer();
    }
};


onActorOk is a function that is bound to the 'ok' handler of the actor subwindow. If the currently-selected item can be used by the selected actor, we process the use of that item. Otherwise, we play the buzzer SE to signal to the player that it can't be used.

Scene_ItemBase.prototype.onActorCancel = function() {
    this.hideSubWindow(this._actorWindow);
};


onActorCancel is a function that is bound to the 'cancel' handler of the actor subwindow, and simply hides the actor window.

Scene_ItemBase.prototype.determineItem = function() {
    var action = new Game_Action(this.user());
    var item = this.item();
    action.setItemObject(item);
    if (action.isForFriend()) {
        this.showSubWindow(this._actorWindow);
        this._actorWindow.selectForItem(this.item());
    } else {
        this.useItem();
        this.activateItemWindow();
    }
};


determineItem figures out whether the item in question needs a target, and sets up the actual action associated with the item.

We create a new Game_Action with the item's user as the subject, assigning it to the variable 'action', and set the variable 'item' to the scene's selected item object. Then, we set the item object of the new action to the object in the item variable.

If the action is set to be used on allies (that is to say its scope in the database was set to '1 ally', 'all allies', '1 ally (dead)', 'all allies (dead)' or 'user'), we show the actor subwindow and set up the selection border appropriate to the item in question (highlighting a single actor if the action is single-target, or the whole party if it affects all allies).

If the action is not for allies, we just process using the item and then activate the item window, as no target selection is necessary.

Scene_ItemBase.prototype.useItem = function() {
    this.playSeForItem();
    this.user().useItem(this.item());
    this.applyItem();
    this.checkCommonEvent();
    this.checkGameover();
    this._actorWindow.refresh();
};


useItem processes the use of the selected item or skill.

First, we play the SE for "use item" or "use skill" depending on which command was chosen. Then, the user uses the item (pays the cost and consumes any consumables involved). Effects are applied, we check whether using the item activated any common events, then check whether using the item resulted in a game over, and finally refresh the actor window (to reflect any changes in HP, MP, level etc).

Scene_ItemBase.prototype.activateItemWindow = function() {
    this._itemWindow.refresh();
    this._itemWindow.activate();
};


activateItemWindow refreshes the item window and then activates it. Simples!

Scene_ItemBase.prototype.itemTargetActors = function() {
    var action = new Game_Action(this.user());
    action.setItemObject(this.item());
    if (!action.isForFriend()) {
        return [];
    } else if (action.isForAll()) {
        return $gameParty.members();
    } else {
        return [$gameParty.members()[this._actorWindow.index()]];
    }
};


itemTargetActors returns the actor/actors being targeted by an item.

First, we create a new Game_Action with the scene's user as the subject and assign it to 'action', then set the item object of action to the item being used.

If the item is not for some combination of allies, we return an empty array because nobody can be targeted by it. Otherwise, if the action is for the whole party, we return the array of party members. Otherwise, we return an array element consisting of the party member corresponding to the actor window's chosen index (even though it's only one actor, the code that deals with the return value from this function uses a function of Array, so it needs to be an array to work).

Scene_ItemBase.prototype.canUse = function() {
    return this.user().canUse(this.item()) && this.isItemEffectsValid();
};


canUse determines whether an item can be used, and returns the result of checking that the user can use the item AND the item has valid effects for the target.

Scene_ItemBase.prototype.isItemEffectsValid = function() {
    var action = new Game_Action(this.user());
    action.setItemObject(this.item());
    return this.itemTargetActors().some(function(target) {
        return action.testApply(target);
    }, this);
};


isItemEffectsValid checks that the item being used has effects that are relevant to the selected target.

A new Game_Action is created with user as the subject and assigned to action, which then has its item object set to the item that was chosen.

The return value looks quite complex, but it's not too bad. Basically, we check whether any actor object in the itemTargetActors array returns true when provided as an argument to the action's testApply function. In other words, we "virtually" test out the item as if we'd used it, and if something happened then the item has valid effects.

[NEW CONCEPT: ARRAY.SOME]
Arrays have a handy little function available to them called 'some', which tests whether any element in the array passes the test implemented by the provided function. The function can take up to three parameters: currentValue (the element currently being checked), index (the index of the checked element), and array (the original array that the element came from). In the case of the above function, we're only using currentValue, but we're calling it "target" to make it clearer what's being passed in.


[NEW CONCEPT: FUNCTIONS AS ARGUMENTS]
For the most part when we've looked at function calls, the values passed in have been either value types (integers, strings etc.) or game objects. However, Javascript fully supports providing an entire function as an argument to another function! As we see with Array.some, it's a function that takes a function as a parameter. You can either write a named function separately and reference it by name in the call, or you can just write the entire function in the brackets, which saves you having to explicitly name a function you're only going to use once.

Note that we've actually already seen this once before in part 1 with Scene_Base's updateChildren function, but I kind of glossed over the concept at the time as we were just starting out.


Scene_ItemBase.prototype.applyItem = function() {
    var action = new Game_Action(this.user());
    action.setItemObject(this.item());
    this.itemTargetActors().forEach(function(target) {
        for (var i = 0; i < action.numRepeats(); i++) {
            action.apply(target);
        }
    }, this);
    action.applyGlobal();
};


applyItem is the function that actually applies the item's effects.

As before, we create a new action and set its object to the used item. Then we iterate through each element of itemTargetActors, executing a function on each one which runs a for loop from 0 to the number of times the item is set to repeat, and applies the action to the target.

Finally, we call applyGlobal, which despite the name actually just reserves any common events activated by the item.

Scene_ItemBase.prototype.checkCommonEvent = function() {
    if ($gameTemp.isCommonEventReserved()) {
        SceneManager.goto(Scene_Map);
    }
};


checkCommonEvent checks whether a common event is reserved by $gameTemp, and if so passes Scene_Map to SceneManager's goto function.

Scene_Item

Scene_Item.prototype.create = function() {
    Scene_ItemBase.prototype.create.call(this);
    this.createHelpWindow();
    this.createCategoryWindow();
    this.createItemWindow();
    this.createActorWindow();
};


The create function calls the base create, then creates windows for help text, item categories, the items themselves, and actors (in case the item is a for-ally consumable we need an actor window for targets).

Scene_Item.prototype.createCategoryWindow = function() {
    this._categoryWindow = new Window_ItemCategory();
    this._categoryWindow.setHelpWindow(this._helpWindow);
    this._categoryWindow.y = this._helpWindow.height;
    this._categoryWindow.setHandler('ok',     this.onCategoryOk.bind(this));
    this._categoryWindow.setHandler('cancel', this.popScene.bind(this));
    this.addWindow(this._categoryWindow);
};


createCategoryWindow creates the window that lists item categories in the scene. First, we create a new instance of Window_ItemCategory, assign it to _categoryWindow, and set its help window to this instance's _helpWindow. We also set its y coordinate to the help window height, so that it will appear underneath. Finally, we set the 'ok' handler to an onCategoryOk binding, 'cancel' to a popScene binding, and then add _categoryWindow to the window layer.

Scene_Item.prototype.createItemWindow = function() {
    var wy = this._categoryWindow.y + this._categoryWindow.height;
    var wh = Graphics.boxHeight - wy;
    this._itemWindow = new Window_ItemList(0, wy, Graphics.boxWidth, wh);
    this._itemWindow.setHelpWindow(this._helpWindow);
    this._itemWindow.setHandler('ok',     this.onItemOk.bind(this));
    this._itemWindow.setHandler('cancel', this.onItemCancel.bind(this));
    this.addWindow(this._itemWindow);
    this._categoryWindow.setItemWindow(this._itemWindow);
};


createItemWindow creates the window that lists the items for each category. We set local variable wy to the category window's y coordinate plus its height: this gives us the Y coordinate where the category window ends. wh is set to the game window height minus wy, which gives us the amount of space between the end of the category window and the bottom of the screen.

We create a new Window_ItemList starting at (0, wy), the width of the game window and wh pixels high. This will create a window that spans the screen width and takes up the rest of the remaining space below the categories. We set the item window's help window to the _helpWindow of the scene, and then set its handlers (onItemOk for 'ok' and onItemCancel for 'cancel'). Then we add the item window to the window layer, and set the item window of the category window to the newly-created one.

Essentially what this last bit does is creates an "anchor" between the category window and the item window; this is how the item window knows what to display when you select a new category.

Scene_Item.prototype.user = function() {
    var members = $gameParty.movableMembers();
    var bestActor = members[0];
    var bestPha = 0;
    for (var i = 0; i < members.length; i++) {
        if (members[i].pha > bestPha) {
            bestPha = members[i].pha;
            bestActor = members[i];
        }
    }
    return bestActor;
};


The user function determines who the user of the item is. We set a local variable 'members' to the result of calling $gameParty's movableMembers function, which returns an array of Game_Actor objects consisting of party members who are currently able to act. bestActor is set to the party member at the first index (0) and bestPha is initialised to 0.

We then have a for loop with "i", repeating as long as i is less than the number of movable members. If the pharmacology Sp-Parameter of the current member is greater than bestPha, we set bestPha to that member's pharmacology and bestActor to that actor.

Finally, we return bestActor.

So that's all well and good, but what does this actually do? Well, it turns out that while you're in the menu, the "user" of an item is considered to be the party member with the highest PHA of those who are capable of acting (i.e. not dead/KOed). In other words, "the potion will be administered by whoever is best at using potions".

Scene_Item.prototype.onCategoryOk = function() {
    this._itemWindow.activate();
    this._itemWindow.selectLast();
};


The onCategoryOk function will be called by the handler for 'ok' input in the category window. It just activates the item window and selects its most recently-used item.

Scene_Item.prototype.onItemOk = function() {
    $gameParty.setLastItem(this.item());
    this.determineItem();
};


The onItemOk function will be called by the handler for 'ok' input in the item window. It sets the party's last-used item to the selected item and then calls determineItem, which we already looked at in Scene_ItemBase.

Scene_Item.prototype.onItemCancel = function() {
    this._itemWindow.deselect();
    this._categoryWindow.activate();
};


The onItemCancel function will be called by the handler for 'cancel' input in the item window. Simply deselects the item window and activates the category window.

Scene_Item.prototype.playSeForItem = function() {
    SoundManager.playUseItem();
};


playSeForItem just plays the sound effect associated with item use as defined in the database, by calling the playUseItem function of SoundManager.

Scene_Item.prototype.useItem = function() {
    Scene_ItemBase.prototype.useItem.call(this);
    this._itemWindow.redrawCurrentItem();
};


useItem first calls its base function and then adds a line specific to Scene_Item, which redraws the current item in the item window, which among other things updates the quantity display.

Scene_Skill

Scene_Skill.prototype.create = function() {
    Scene_ItemBase.prototype.create.call(this);
    this.createHelpWindow();
    this.createSkillTypeWindow();
    this.createStatusWindow();
    this.createItemWindow();
    this.createActorWindow();
    this.refreshActor();
};


The create function calls the base create, then creates windows for help, skill type selection, actor status (user), items (which in this case are skills), and actor (target), then calls refreshActor to associate the various windows with the actor whose skills we're currently looking at.

Scene_Skill.prototype.createSkillTypeWindow = function() {
    var wy = this._helpWindow.height;
    this._skillTypeWindow = new Window_SkillType(0, wy);
    this._skillTypeWindow.setHelpWindow(this._helpWindow);
    this._skillTypeWindow.setHandler('skill',    this.commandSkill.bind(this));
    this._skillTypeWindow.setHandler('cancel',   this.popScene.bind(this));
    this._skillTypeWindow.setHandler('pagedown', this.nextActor.bind(this));
    this._skillTypeWindow.setHandler('pageup',   this.previousActor.bind(this));
    this.addWindow(this._skillTypeWindow);
};


createSkillTypeWindow first sets a local variable, wy, to the height of the help window. Then we create a new instance of Window_SkillType at (0, wy) and assign it to _skillTypeWindow. We set the skill type window's help window to _helpWindow, then bind the commandSkill, popScene, nextActor and previousActor functions to the 'skill', 'cancel', 'pagedown' and 'pageup' handlers respectively. Finally, we add the skill type window to the window layer.

Scene_Skill.prototype.createStatusWindow = function() {
    var wx = this._skillTypeWindow.width;
    var wy = this._helpWindow.height;
    var ww = Graphics.boxWidth - wx;
    var wh = this._skillTypeWindow.height;
    this._statusWindow = new Window_SkillStatus(wx, wy, ww, wh);
    this.addWindow(this._statusWindow);
};


createStatusWindow sets several local variables: wx to the skill type window's width, wy to the help window's height, ww to the game window width less wx, and wh to the height of the skill type window. Then we create a new instance of Window_SkillStatus at (wx, wy) which is ww pixels wide and wh pixels tall, assigning it to _statusWindow, and then we add it to the window layer. This will end up placing the status window to the right of the skill type window and below the help window, with it taking up the rest of the horizontal screen space and the same amount of vertical space as the skill type window does.

Scene_Skill.prototype.createItemWindow = function() {
    var wx = 0;
    var wy = this._statusWindow.y + this._statusWindow.height;
    var ww = Graphics.boxWidth;
    var wh = Graphics.boxHeight - wy;
    this._itemWindow = new Window_SkillList(wx, wy, ww, wh);
    this._itemWindow.setHelpWindow(this._helpWindow);
    this._itemWindow.setHandler('ok',     this.onItemOk.bind(this));
    this._itemWindow.setHandler('cancel', this.onItemCancel.bind(this));
    this._skillTypeWindow.setSkillWindow(this._itemWindow);
    this.addWindow(this._itemWindow);
};


createItemWindow also sets several local variables: wx to 0, wy to the y coordinate of the status window plus its height, ww to the game window width, and wh to the game window height less wy. Then, we create a new instance of Window_SkillList at (wx, wy) which is ww pixels wide and wh pixels tall and assign it to _itemWindow. This will place it at the far left of the screen just under the status window, with it taking up the entire remainder of the available screen space.

Then, _itemWindow's help window is set to _helpWindow, and we bind the onItemOk and onItemCancel functions to its 'ok' and 'cancel' handlers. Finally, we add it to the window layer.

Scene_Skill.prototype.refreshActor = function() {
    var actor = this.actor();
    this._skillTypeWindow.setActor(actor);
    this._statusWindow.setActor(actor);
    this._itemWindow.setActor(actor);
};


refreshActor...have a guess. We set the variable actor to the result of calling the scene's actor function (which as we saw in Scene_MenuBase just returns its _actor variable) then we call the setActor function of the skill type, status and item windows, passing in actor. This allows each window to reflect the details of the actor currently on screen.

Scene_Skill.prototype.user = function() {
    return this.actor();
};


The user function returns the actor using the skill, and simply returns the result of calling the actor function.

Scene_Skill.prototype.commandSkill = function() {
    this._itemWindow.activate();
    this._itemWindow.selectLast();
};


The commandSkill function is the one we bound to the 'skill' handler of the skill type window, which means it will be called when selecting any skill type from the list. It activates the item window and selects the most recently-used skill.

Scene_Skill.prototype.onItemOk = function() {
    this.actor().setLastMenuSkill(this.item());
    this.determineItem();
};


The onItemOk function is the one we bound to the 'ok' handler of the item window. We set the current actor's last-used menu skill to the one currently selected, then call determineItem to either show the target window or use the skill if no targets are needed.

Scene_Skill.prototype.onItemCancel = function() {
    this._itemWindow.deselect();
    this._skillTypeWindow.activate();
};


The onItemCancel function is the one we bound to the 'cancel' handler of the item window. It just deselects the item window and activates the skill type window.

Scene_Skill.prototype.playSeForItem = function() {
    SoundManager.playUseSkill();
};


The playSeForItem function plays the sound effect associated with skill use by calling the playUseSkill function of SoundManager.

Scene_Skill.prototype.useItem = function() {
    Scene_ItemBase.prototype.useItem.call(this);
    this._statusWindow.refresh();
    this._itemWindow.refresh();
};


This overwrite of useItem first calls the base useItem function, then refreshes the status and item windows. This updates HP, MP, enabled colours for skills etc.

Scene_Skill.prototype.onActorChange = function() {
    this.refreshActor();
    this._skillTypeWindow.activate();
};


onActorChange refreshes the actor and activates the skill type window. As we saw before, this is called by nextActor and previousActor, which we bound to page up and page down, meaning that when we "page" to a different actor, we'll end up back at the skill type selection.

And that's it for now! Next time I'll continue the breakdown of Scene_MenuBase child classes, starting with Scene_Equip. As always, comments and suggestions are welcomed.

Until next time!