JUMP INTO JAVASCRIPT PART 5

The teardown series nears the end of scenes.

  • Trihan
  • 02/14/2017 10:12 AM
  • 2418 views
[insert generic sports fan greeting here]! You know what time it is. That's right, it's time for another exciting action-packed* episode of


Jump into Javascript

Now let me equip you with some more Javascript knowledge. You can use it as a weapon against ignorance and armour to protect you from bad code. Oh yeah, I am the pun master. Let's do this.

Scene_Equip

Scene_Equip.prototype.create = function() {
    Scene_MenuBase.prototype.create.call(this);
    this.createHelpWindow();
    this.createStatusWindow();
    this.createCommandWindow();
    this.createSlotWindow();
    this.createItemWindow();
    this.refreshActor();
};


The create function is pretty standard fare for this kind of scene by now but as it isn't identical to the others we're still gonna break it down. So we call the super function and then we create a help window and then we create a status window and then we create a command window and then we create a slot window and then we create an item window and then we refresh the actor. That's a lot of windows. Most are self-explanatory, though just in case you can't tell the slot window is the one where you choose which slot to equip.

Scene_Equip.prototype.createStatusWindow = function() {
    this._statusWindow = new Window_EquipStatus(0, this._helpWindow.height);
    this.addWindow(this._statusWindow);
};


createStatusWindow is pretty simple; we create a new instance of Window_EquipStatus, passing in an X coordinate of 0 and a Y coordinate of the help window's height, then add it to the window layer. This will place it at the far left underneath the help window.

Scene_Equip.prototype.createCommandWindow = function() {
    var wx = this._statusWindow.width;
    var wy = this._helpWindow.height;
    var ww = Graphics.boxWidth - this._statusWindow.width;
    this._commandWindow = new Window_EquipCommand(wx, wy, ww);
    this._commandWindow.setHelpWindow(this._helpWindow);
    this._commandWindow.setHandler('equip',    this.commandEquip.bind(this));
    this._commandWindow.setHandler('optimize', this.commandOptimize.bind(this));
    this._commandWindow.setHandler('clear',    this.commandClear.bind(this));
    this._commandWindow.setHandler('cancel',   this.popScene.bind(this));
    this._commandWindow.setHandler('pagedown', this.nextActor.bind(this));
    this._commandWindow.setHandler('pageup',   this.previousActor.bind(this));
    this.addWindow(this._commandWindow);
};


createCommandWindow is pretty similar to the other ones we've looked at previously but with some placement variables being set first. So we set wx to the status window's width, and wy to the help window's height, and ww to the width of the game box less the status window's width. These are passed in as arguments to a new instance of Window_EquipCommand, meaning that the window will be to the right of the status window and underneath the help window, and will be as wide as there is available space to the right of the status window. The new instance is assigned to _commandWindow.

The rest is stuff we've seen before; we set the help window for this window to _helpWindow, and then bind commandEquip to the 'equip' handler, commandOptimize to the 'optimize' handler, commandClear to the 'clear' handler, popScene to the 'cancel' handler, nextActor to the 'pagedown' handler, and previousActor to the 'pageup' handler. Then we add the window to the window layer.

Scene_Equip.prototype.createSlotWindow = function() {
    var wx = this._statusWindow.width;
    var wy = this._commandWindow.y + this._commandWindow.height;
    var ww = Graphics.boxWidth - this._statusWindow.width;
    var wh = this._statusWindow.height - this._commandWindow.height;
    this._slotWindow = new Window_EquipSlot(wx, wy, ww, wh);
    this._slotWindow.setHelpWindow(this._helpWindow);
    this._slotWindow.setStatusWindow(this._statusWindow);
    this._slotWindow.setHandler('ok',       this.onSlotOk.bind(this));
    this._slotWindow.setHandler('cancel',   this.onSlotCancel.bind(this));
    this.addWindow(this._slotWindow);
};


createSlotWindow does much the same thing without the commands; we set wx to the width of the status window, wy to the command window's Y coordinate plus its height, ww to the width of the game box less the width of the status window, and wh to the height of the status window less the height of the command window. This will end up placing the slot window to the right of the status window, underneath the command window, as wide as there is available space left and as tall as the space between the bottom of the command window and the bottom of the status window.

We pass these values as arguments to a new instance of Window_EquipSlot, which we assign to _slotWindow. Then we set the help window to _helpWindow, the status window to _statusWindow, and bind a couple of functions: onSlotOk to the 'ok' handler, and onSlotCancel to the 'cancel' handler. Finally, we add the _slotWindow to the window layer.

Scene_Equip.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_EquipItem(wx, wy, ww, wh);
    this._itemWindow.setHelpWindow(this._helpWindow);
    this._itemWindow.setStatusWindow(this._statusWindow);
    this._itemWindow.setHandler('ok',     this.onItemOk.bind(this));
    this._itemWindow.setHandler('cancel', this.onItemCancel.bind(this));
    this._slotWindow.setItemWindow(this._itemWindow);
    this.addWindow(this._itemWindow);
};


createItemWindow sets wx to 0, wy to the status window's Y coordinate plus its height, ww to the width of the game box, and wh to the height of the game box less wy. This will place the item window at the far left, under the status window, as wide as the game box and taking up the remaining space between the bottom of the status window and the bottom of the screen. We pass these values as arguments to a new instance of Window_EquipItem and assign the new instance to _itemWindow.

Then we set its help window to _helpWindow and its status window to _statusWindow. We bind onItemOk to the 'ok' handler and onItemCancel to the 'cancel' handler. We also set _slotWindow's item window to the one we just created, and finally we add _itemWindow to the window layer.

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


Very similar to the refreshActor function from Scene_Skill, though this one calls setActor for _slotWindow instead of_skillTypeWindow. Everything else is the same.

Scene_Equip.prototype.commandEquip = function() {
    this._slotWindow.activate();
    this._slotWindow.select(0);
};


commandEquip is the function we bound to the 'equip' handler of the equip command window. It activates the slot window and selects the first item in it (which will be weapon unless you've customised your slots somehow).

Scene_Equip.prototype.commandOptimize = function() {
    SoundManager.playEquip();
    this.actor().optimizeEquipments();
    this._statusWindow.refresh();
    this._slotWindow.refresh();
    this._commandWindow.activate();
};


commandOptimize is the function we bound to the 'optimize' handler of the equip command window. It plays the 'Equip' sound from the database and calls the optimizeEquipments function on the current actor. Finally, we refresh the status/slot windows and activate the command window. Though we won't be tearing that one down for a while, from what I've looked at so far the optimize function in MV is vastly superior to the one from VX Ace, <shamelessplug>though not by so much that I'm not tempted to port my Equipment Optimisation Enhanced script as an MV plugin at some point in the near future.</shamelessplug>

Scene_Equip.prototype.commandClear = function() {
    SoundManager.playEquip();
    this.actor().clearEquipments();
    this._statusWindow.refresh();
    this._slotWindow.refresh();
    this._commandWindow.activate();
};


commandClear is the function we bound to the 'clear' handler of the equip command window. Does exactly the same as the previous function only it calls clearEquipments instead.

Scene_Equip.prototype.onSlotOk = function() {
    this._itemWindow.activate();
    this._itemWindow.select(0);
};


onSlotOk is the function we bound to the 'ok' handler of the equip slot window. It activates the item window and selects its first item.

Scene_Equip.prototype.onSlotCancel = function() {
    this._slotWindow.deselect();
    this._commandWindow.activate();
};


onSlotCancel is the function we bound to the 'cancel' handler of the equip slot window. It deselects the slot window and activates the command window.

Scene_Equip.prototype.onItemOk = function() {
    SoundManager.playEquip();
    this.actor().changeEquip(this._slotWindow.index(), this._itemWindow.item());
    this._slotWindow.activate();
    this._slotWindow.refresh();
    this._itemWindow.deselect();
    this._itemWindow.refresh();
    this._statusWindow.refresh();
};


onItemOk is the function we bound to the 'ok' handler of the equip item window. It plays the 'Equip' sound from the database, and calls changeEquip on the current actor passing in the slow window's index and the item object from the item window. Then we activate the slot window and refresh it, deselect the item window and refresh it, and refresh the status window. This will reflect changes to the slot, item quantities, item layout, the actor's stats, and other things that might need visual updates.

Scene_Equip.prototype.onItemCancel = function() {
    this._slotWindow.activate();
    this._itemWindow.deselect();
};


onItemCancel is the function we bound to the 'cancel' handler of the equip item window. It activates the slot window and deselects the item window.

Scene_Equip.prototype.onActorChange = function() {
    this.refreshActor();
    this._commandWindow.activate();
};


The overwrite of onActorChange refreshes the actor and activates the command window, so whenever you page between actors it's always reset to have commands selected.

Scene_Status

Scene_Status.prototype.create = function() {
    Scene_MenuBase.prototype.create.call(this);
    this._statusWindow = new Window_Status();
    this._statusWindow.setHandler('cancel',   this.popScene.bind(this));
    this._statusWindow.setHandler('pagedown', this.nextActor.bind(this));
    this._statusWindow.setHandler('pageup',   this.previousActor.bind(this));
    this.addWindow(this._statusWindow);
    this.refreshActor();
};


Status window is nice and simple, without the clutter of myriad subwindows. We call the super function, then create a new Window_Status assigned to _statusWindow. We bind popScene to the 'cancel' handler, nextActor to the 'pagedown' handler and previousActor to the 'pageup' handler, then add _statusWindow to the window layer and refresh the actor.

Scene_Status.prototype.refreshActor = function() {
    var actor = this.actor();
    this._statusWindow.setActor(actor);
};


As with the other refresh functions, we set actor to the currently-selected actor and then call the setActor function for each window in the scene that relies on actor information, which in this case is just _statusWindow.

Scene_Options

Scene_Options.prototype.create = function() {
    Scene_MenuBase.prototype.create.call(this);
    this.createOptionsWindow();
};


The create function is as simple as they come, really: call the super function, then create the options window. As we'll see in a second, I'm not sure why they didn't just create the options window directly here like they did with Scene_Status, but it is what it is.

Scene_Options.prototype.terminate = function() {
    Scene_MenuBase.prototype.terminate.call(this);
    ConfigManager.save();
};


The options scene is the first one to overwrite the terminate function from Scene_MenuBase, and adds an additional line which saves the configuration by calling the save function of ConfigManager. This ensures that when you leave the options menu your changes are retained.

Scene_Options.prototype.createOptionsWindow = function() {
    this._optionsWindow = new Window_Options();
    this._optionsWindow.setHandler('cancel', this.popScene.bind(this));
    this.addWindow(this._optionsWindow);
};


The createOptionsWindow function does nothing we haven't seen before. Create a new instance of Window_Options assigned to _optionsWindow, bind popScene to its 'cancel' handler, then add _optionsWindow to the window layer. Yawn.

Scene_File

Scene_File.prototype.create = function() {
    Scene_MenuBase.prototype.create.call(this);
    DataManager.loadAllSavefileImages();
    this.createHelpWindow();
    this.createListWindow();
};


The create function for Scene_File calls the super function, then loads the save file images (this loads in all of the character images displayed on save files), and then creates help and list windows.

Scene_File.prototype.start = function() {
    Scene_MenuBase.prototype.start.call(this);
    this._listWindow.refresh();
};


This overwrite of the start function calls the super function from Scene_MenuBase and then refreshes the list window.

Scene_File.prototype.savefileId = function() {
    return this._listWindow.index() + 1;
};


savefileId is a getter function which returns the list window's index plus 1. (this gives us a 1-indexed file ID from a 0-indexed variable).

Scene_File.prototype.createHelpWindow = function() {
    this._helpWindow = new Window_Help(1);
    this._helpWindow.setText(this.helpWindowText());
    this.addWindow(this._helpWindow);
};


createHelpWindow does what it says on the tin and creates a new instance of Window_Help 1 line high (it's 2 by default if you don't pass in a value) assigned to _helpWindow. We set the text of the help window to the result of calling helpWindowText, which as we'll see shortly just sets it to a blank string (in the base class at least), and then add _helpWindow to the window layer.

Scene_File.prototype.createListWindow = function() {
    var x = 0;
    var y = this._helpWindow.height;
    var width = Graphics.boxWidth;
    var height = Graphics.boxHeight - y;
    this._listWindow = new Window_SavefileList(x, y, width, height);
    this._listWindow.setHandler('ok',     this.onSavefileOk.bind(this));
    this._listWindow.setHandler('cancel', this.popScene.bind(this));
    this._listWindow.select(this.firstSavefileIndex());
    this._listWindow.setTopRow(this.firstSavefileIndex() - 2);
    this._listWindow.setMode(this.mode());
    this._listWindow.refresh();
    this.addWindow(this._listWindow);
};


createListWindow sets variable x to 0 and y to the height of the help window, width to the box width and height to the box height less y, and passes these as arguments to a new instance of Window_SaveFileList assigned to _listWindow. This will display the window at the far left under the help window, taking up the remainder of the screen.

We bind onSavefileOk to the 'ok' handler and popScene to the 'cancel' handler, then select the first save file index (which will always be 0 in the base class but will be overwritten by child classes as we'll see), set the top row to the first index minus 2 with a minimum of 0 (which will display the most recently saved file in the middle of the list unless you've reached the bottom of it), sets the mode to the result of calling mode (which in the base class returns null), refreshes the list window, and finally adds _listWindow to the window layer.

Scene_File.prototype.mode = function() {
    return null;
};


mode in the base file scene returns null. This will be overwritten in child classes.

Scene_File.prototype.activateListWindow = function() {
    this._listWindow.activate();
};


Funnily enough, the activateListWindow function activates the list window.

Scene_File.prototype.helpWindowText = function() {
    return '';
};


helpWindowText simply returns a blank string. This will be overwritten in child classes.

Scene_File.prototype.firstSavefileIndex = function() {
    return 0;
};


firstSaveFileIndex simply returns 0. This will be overwritten in child classes.

Scene_File.prototype.onSavefileOk = function() {
};


onSaveFileOk doesn't do anything. Again, this will be overwritten.

Scene_Save

Scene_Save.prototype.mode = function() {
    return 'save';
};


The overwritten mode function for this scene returns 'save'.

Scene_Save.prototype.helpWindowText = function() {
    return TextManager.saveMessage;
};


the overwritten helpWindowText function for this scene returns the save game message from TextManager, which will be whatever text was set in the "Save Message" term in the database.

Scene_Save.prototype.firstSavefileIndex = function() {
    return DataManager.lastAccessedSavefileId() - 1;
};


The overwritten firstSavefileIndex function returns 1 less than the lastAccessedSavefileId property of DataManager. This basically means the actual 0-indexed ID of the most recently saved file.

Scene_Save.prototype.onSavefileOk = function() {
    Scene_File.prototype.onSavefileOk.call(this);
    $gameSystem.onBeforeSave();
    if (DataManager.saveGame(this.savefileId())) {
        this.onSaveSuccess();
    } else {
        this.onSaveFailure();
    }
};


The overwritten onSavefileOk function first calls the super function (god knows why, it doesn't do anything), then calls the onBeforeSave function of $gameSystem, which updates some system data prior to saving (as we'll see when we finally get around to rpg_objects.js).

If we are able to successfully call the saveGame function of DataManager passing in the scene's save file ID (which is to say the call returns true) we call onSaveSuccess. Otherwise, we call onSaveFailure.

Scene_Save.prototype.onSaveSuccess = function() {
    SoundManager.playSave();
	StorageManager.cleanBackup(this.savefileId());
    this.popScene();
};


The onSaveSuccess function is called when the game is saved successfully. First we play the save sound from the database, then cleans the backup creates before attempting to save (as we'll see when we look at rpg_managers.js, a backup of the game data is created just in case something goes wrong during the save, in which case the backup is restored) and finally we call popScene to return to the previous scene.

Scene_Save.prototype.onSaveFailure = function() {
    SoundManager.playBuzzer();
    this.activateListWindow();
};


The onSaveFailure function is called when the game fails to save. First we play the buzzer sound from the database, then activate the list window.

Scene_Load

Scene_Load.prototype.initialize = function() {
    Scene_File.prototype.initialize.call(this);
    this._loadSuccess = false;
};


Been a while since a scene overwrote initialize! The one for Scene_Load first calls the base Scene_File initialize function, then sets the _loadSuccess variable to false.

Scene_Load.prototype.terminate = function() {
    Scene_File.prototype.terminate.call(this);
    if (this._loadSuccess) {
        $gameSystem.onAfterLoad();
    }
};


The overwritten terminate function first calls the one for the base class, then if _loadSuccess is true we call the onAfterLoad function of $gameSystem, which retrieves some of the data that onBeforeSave set.

Scene_Load.prototype.mode = function() {
    return 'load';
};


Surprise surprise, the overwritten mode function in Scene_Load returns 'load'. Who'da thunkit?

Scene_Load.prototype.helpWindowText = function() {
    return TextManager.loadMessage;
};


In other shocking news, the overwritten helpWindowText function returns TextManager's loadMessage property, which will be the Load Message entry from the terms tab of the database.

Scene_Load.prototype.firstSavefileIndex = function() {
    return DataManager.latestSavefileId() - 1;
};


In Scene_Load, the firstSavefileIndex function returns 1 less than DataManager's latest save file ID. Note that this is slightly different from lastAccessedSavefileId: the latter is the most recent ID that was used for a saved game, while the former is the save ID with the most recent timestamp. In practice these will pretty much always end up being the same value, but it's handy to note that they're getting their values from different functions anyway.

Scene_Load.prototype.onSavefileOk = function() {
    Scene_File.prototype.onSavefileOk.call(this);
    if (DataManager.loadGame(this.savefileId())) {
        this.onLoadSuccess();
    } else {
        this.onLoadFailure();
    }
};


This is identical to the overwrite from Scene_Save except we're not calling $gameSystem.onBeforeSave() and we're calling loadGame instead of saveGame.

Scene_Load.prototype.onLoadSuccess = function() {
    SoundManager.playLoad();
    this.fadeOutAll();
    this.reloadMapIfUpdated();
    SceneManager.goto(Scene_Map);
    this._loadSuccess = true;
};


The onLoadSuccess function first plays the load game sound from the database. Then we call fadeOutAll to fade the screen (which you may not remember from way back in Scene_Base but we did look at it), then reloadMapIfUpdated, then the goto function of SceneManager passing in Scene_Map, and finally we set _loadSuccess to true.

Scene_Load.prototype.onLoadFailure = function() {
    SoundManager.playBuzzer();
    this.activateListWindow();
};


onLoadFailure is more or less identical to onSaveFailure: We play the buzzer sound from the database, then activate the list window.

Scene_Load.prototype.reloadMapIfUpdated = function() {
    if ($gameSystem.versionId() !== $dataSystem.versionId) {
        $gamePlayer.reserveTransfer($gameMap.mapId(), $gamePlayer.x, $gamePlayer.y);
        $gamePlayer.requestMapReload();
    }
};


reloadMapIfUpdated first checks to see if the version ID in $gameSystem has changed. If so, we reserve a player transfer to the player's current map and position, then call the player's requestMapReload function, which sets the "needs map reload" flag to true. Version ID is randomly generated when you save your project, so basically this will ensure that any changes made to the game after it was saved are appropriately loaded in to a previously saved game (if you add events to a map or change the tiles, for instance).

Scene_GameEnd

Scene_GameEnd.prototype.create = function() {
    Scene_MenuBase.prototype.create.call(this);
    this.createCommandWindow();
};


Nothing special in this scene's create function, it just calls the super create function and then creates a command window.

Scene_GameEnd.prototype.stop = function() {
    Scene_MenuBase.prototype.stop.call(this);
    this._commandWindow.close();
};


The overwritten stop function calls the super version and then closes the command window (this animates it closing rather than it just disappearing).

Scene_GameEnd.prototype.createBackground = function() {
    Scene_MenuBase.prototype.createBackground.call(this);
    this.setBackgroundOpacity(128);
};


The overwritten createBackground function calls the super function and then sets the background opacity to 128, or half-transparent.

Scene_GameEnd.prototype.createCommandWindow = function() {
    this._commandWindow = new Window_GameEnd();
    this._commandWindow.setHandler('toTitle',  this.commandToTitle.bind(this));
    this._commandWindow.setHandler('cancel',   this.popScene.bind(this));
    this.addWindow(this._commandWindow);
};


The createCommandWindow function creates a new instance of Window_GameEnd assigned to _commandWindow, binds commandToTitle to its 'toTitle' handler and popScene to its 'cancel' handler, then adds it to the window layer.

Scene_GameEnd.prototype.commandToTitle = function() {
    this.fadeOutAll();
    SceneManager.goto(Scene_Title);
};


commandToTitle is the function that was bound to the command window's 'toTitle' handler; it fades out the screen and then has SceneManager go to the title scene.

Scene_Shop

Scene_Shop.prototype.prepare = function(goods, purchaseOnly) {
    this._goods = goods;
    this._purchaseOnly = purchaseOnly;
    this._item = null;
};


The prepare function of Scene_Shop takes two parameters: goods and purchaseOnly. We set _goods to the passed-in goods (which is an array of goods the shop sells), _purchaseOnly is set to the passed-in purchaseOnly (true or false depending on whether the player can sell items as well as buy them) and finally we set _item to null.

Scene_Shop.prototype.create = function() {
    Scene_MenuBase.prototype.create.call(this);
    this.createHelpWindow();
    this.createGoldWindow();
    this.createCommandWindow();
    this.createDummyWindow();
    this.createNumberWindow();
    this.createStatusWindow();
    this.createBuyWindow();
    this.createCategoryWindow();
    this.createSellWindow();
};


This scene has windows galore! Okay, so for create we (as always) call the super function. Then we create a help window, a gold window, a command window, a dummy window, a number window, a status window, a buy window, a category window and a sell window.

Scene_Shop.prototype.createGoldWindow = function() {
    this._goldWindow = new Window_Gold(0, this._helpWindow.height);
    this._goldWindow.x = Graphics.boxWidth - this._goldWindow.width;
    this.addWindow(this._goldWindow);
};


createGoldWindow creates a new instance of Window_Gold passing in 0 for the X coordinate and the help window's height for the Y coordinate, assigned to _goldwindow. Its X coordinate is then set to the game box width minus the width of the gold window. This places it at the top right of the screen (we couldn't set the X in the first line because the window didn't exist yet, so we didn't know how wide it was. Theoretically as the window is hardcoded at 240 pixels wide we could have just done Graphics.boxWidth - 240, but the default code is set up to make changing values easier). Finally, as with all windows, we add _goldWindow to the window layer.

Scene_Shop.prototype.createCommandWindow = function() {
    this._commandWindow = new Window_ShopCommand(this._goldWindow.x, this._purchaseOnly);
    this._commandWindow.y = this._helpWindow.height;
    this._commandWindow.setHandler('buy',    this.commandBuy.bind(this));
    this._commandWindow.setHandler('sell',   this.commandSell.bind(this));
    this._commandWindow.setHandler('cancel', this.popScene.bind(this));
    this.addWindow(this._commandWindow);
};


createCommandWindow creates a new instance of Window_ShopCommand, passing in the gold window's X coordinate and the value of _purchaseOnly, assigned to _commandWindow. The command window's Y coordinate is set to the help window's height (this one couldn't have been done in the constructor as Window_ShopCommand doesn't have a parameter for Y coordinate), and then we bind commandBuy to the 'buy' handler, commandSell to the 'sell' handler, and popScene to the 'cancel' handler. Finally, _commandWindow is added to the window layer.

Scene_Shop.prototype.createDummyWindow = function() {
    var wy = this._commandWindow.y + this._commandWindow.height;
    var wh = Graphics.boxHeight - wy;
    this._dummyWindow = new Window_Base(0, wy, Graphics.boxWidth, wh);
    this.addWindow(this._dummyWindow);
};


In createDummyWindow, first we set wy to the command window's Y position plus its height, and then wh to the game box height minus wy. We pass in 0, wy, the box width, and wh to create a new instance of Window_Base assigned to _dummyWindow. This will create a window at the top left underneath the command window, filling the rest of the available screen space. The dummy window is the "blank" window displayed until the player selects buy or sell from the command window.

Scene_Shop.prototype.createNumberWindow = function() {
    var wy = this._dummyWindow.y;
    var wh = this._dummyWindow.height;
    this._numberWindow = new Window_ShopNumber(0, wy, wh);
    this._numberWindow.hide();
    this._numberWindow.setHandler('ok',     this.onNumberOk.bind(this));
    this._numberWindow.setHandler('cancel', this.onNumberCancel.bind(this));
    this.addWindow(this._numberWindow);
};


createNumberWindow sets wy to the dummy window's Y position and wh to its height, then passes 0, wy and wh as arguments to a new instance of Window_ShopNumber which is assigned to _numberWindow (this will position it at the far left at the same vertical point as the dummy window). We then hide the window (because it shouldn't be visible until we need to input a number of something). We bind onNumberOk to the 'ok' handler and onNumberCancel to the 'cancel' handler, then add _numberWindow to the window layer.

Scene_Shop.prototype.createStatusWindow = function() {
    var wx = this._numberWindow.width;
    var wy = this._dummyWindow.y;
    var ww = Graphics.boxWidth - wx;
    var wh = this._dummyWindow.height;
    this._statusWindow = new Window_ShopStatus(wx, wy, ww, wh);
    this._statusWindow.hide();
    this.addWindow(this._statusWindow);
};


createStatusWindow sets wx to the number window's width, wy to the dummy window's y position, ww to the game box width minus wx, and wh to the dummy window's height. These values are passed in as arguments to a new instance of Window_ShopStatus, which is assigned to _statusWindow (this will position the window to the right of the number window, at the same vertical point as the dummy window, and take up the remaining space to the right of the number window). We hide this window as well (because while choosing commands there is no status to show) and finally add _statusWindow to the window layer.

Scene_Shop.prototype.createBuyWindow = function() {
    var wy = this._dummyWindow.y;
    var wh = this._dummyWindow.height;
    this._buyWindow = new Window_ShopBuy(0, wy, wh, this._goods);
    this._buyWindow.setHelpWindow(this._helpWindow);
    this._buyWindow.setStatusWindow(this._statusWindow);
    this._buyWindow.hide();
    this._buyWindow.setHandler('ok',     this.onBuyOk.bind(this));
    this._buyWindow.setHandler('cancel', this.onBuyCancel.bind(this));
    this.addWindow(this._buyWindow);
};


createBuyWindow sets wy to the dummy window's Y position and wh to its height, then passes in 0, wy, wh and the _goods array to a new instance of Window_ShopBuy, assigning it to _buyWindow (this will give it the same starting position and height as the dummy window). We set its help window to _helpWindow, its status window to _statusWindow, and hide it. Then we bind onBuyOk to the 'ok' handler, onBuyCancel to the 'cancel' handler, and add _buyWindow to the window layer.

Scene_Shop.prototype.createCategoryWindow = function() {
    this._categoryWindow = new Window_ItemCategory();
    this._categoryWindow.setHelpWindow(this._helpWindow);
    this._categoryWindow.y = this._dummyWindow.y;
    this._categoryWindow.hide();
    this._categoryWindow.deactivate();
    this._categoryWindow.setHandler('ok',     this.onCategoryOk.bind(this));
    this._categoryWindow.setHandler('cancel', this.onCategoryCancel.bind(this));
    this.addWindow(this._categoryWindow);
};


createCategoryWindow creates a new instance of Window_ItemCategory, sets its help window to _helpWindow, and sets its Y coordinate to the same as the dummy window's. We then hide and deactivate the category window. We bind onCategoryOk to the 'ok' handler and onCategoryCancel to the 'cancel' handler, and then add _categoryWindow to the window layer.

Scene_Shop.prototype.createSellWindow = function() {
    var wy = this._categoryWindow.y + this._categoryWindow.height;
    var wh = Graphics.boxHeight - wy;
    this._sellWindow = new Window_ShopSell(0, wy, Graphics.boxWidth, wh);
    this._sellWindow.setHelpWindow(this._helpWindow);
    this._sellWindow.hide();
    this._sellWindow.setHandler('ok',     this.onSellOk.bind(this));
    this._sellWindow.setHandler('cancel', this.onSellCancel.bind(this));
    this._categoryWindow.setItemWindow(this._sellWindow);
    this.addWindow(this._sellWindow);
};


createSellWindow sets wy to the category window's Y position plus its height, and wh to the game box height minus wy. We create a new instance of Window_ShopSell passing in 0, wy, the box width and wh as arguments (this will position it on the far left, under the category window, taking up the rest of the available space), assigned to _sellWindow. We set its help window to _helpWindow and hide it. Then we bind onSellOk to its 'ok' handler and onSellCancel to its 'cancel' handler, set the category window's item window to _sellWindow, and finally add it to the window layer.

Scene_Shop.prototype.activateBuyWindow = function() {
    this._buyWindow.setMoney(this.money());
    this._buyWindow.show();
    this._buyWindow.activate();
    this._statusWindow.show();
};


activateBuyWindow sets the money variable of the buy window to the value in the gold window (in other words, how much money the party has), shows and activates the buy window, and shows the status window.

Scene_Shop.prototype.activateSellWindow = function() {
    this._categoryWindow.show();
    this._sellWindow.refresh();
    this._sellWindow.show();
    this._sellWindow.activate();
    this._statusWindow.hide();
};


activateSellWindow shows the category window, refreshes, shows and activates the sell window, and hides the status window.

Scene_Shop.prototype.commandBuy = function() {
    this._dummyWindow.hide();
    this.activateBuyWindow();
};


commandBuy is the function we bound to the 'buy' handler of the command window. It hides the dummy window and activates the buy window.

Scene_Shop.prototype.commandSell = function() {
    this._dummyWindow.hide();
    this._categoryWindow.show();
    this._categoryWindow.activate();
    this._sellWindow.show();
    this._sellWindow.deselect();
    this._sellWindow.refresh();
};


commandSell is the function we bound to the 'sell' handler of the command window. It hides the dummy window, shows and activates the category window, then shows, deselects and refreshes the sell window.

Scene_Shop.prototype.onBuyOk = function() {
    this._item = this._buyWindow.item();
    this._buyWindow.hide();
    this._numberWindow.setup(this._item, this.maxBuy(), this.buyingPrice());
    this._numberWindow.setCurrencyUnit(this.currencyUnit());
    this._numberWindow.show();
    this._numberWindow.activate();
};


onBuyOk is the function we bound to the 'ok' handler of the buy window. First we set _item to the buy window's item and hide the buy window, then set up the number window passing in the item, the maximum quantity the party is able to buy, and the buying price of the item. We also set the currency unit for the number window to the gold window's currency unit, then show and activate the number window.

Scene_Shop.prototype.onBuyCancel = function() {
    this._commandWindow.activate();
    this._dummyWindow.show();
    this._buyWindow.hide();
    this._statusWindow.hide();
    this._statusWindow.setItem(null);
    this._helpWindow.clear();
};


onBuyCancel is the function we bound to the 'cancel' handler of the buy window. We activate the command window, show the dummy window, hide the buy window, hide the status window and set its item to null, and finally clear the help window.

Scene_Shop.prototype.onCategoryOk = function() {
    this.activateSellWindow();
    this._sellWindow.select(0);
};


onCategoryOk is the function we bound to the 'ok' handler of the category window; it just activates the sell window and selects the first item in it.

Scene_Shop.prototype.onCategoryCancel = function() {
    this._commandWindow.activate();
    this._dummyWindow.show();
    this._categoryWindow.hide();
    this._sellWindow.hide();
};


onCategoryCancel is the function we bound to the 'cancel' handler of the category window. We activate the command window, show the dummy window, hide the category window and hide the sell window.

Scene_Shop.prototype.onSellOk = function() {
    this._item = this._sellWindow.item();
    this._categoryWindow.hide();
    this._sellWindow.hide();
    this._numberWindow.setup(this._item, this.maxSell(), this.sellingPrice());
    this._numberWindow.setCurrencyUnit(this.currencyUnit());
    this._numberWindow.show();
    this._numberWindow.activate();
    this._statusWindow.setItem(this._item);
    this._statusWindow.show();
};


onSellOk is the function we bound to the 'ok' handler of the sell window. We set the scene's _item variable to the item in the sell window, then hide the category and sell windows. We set up the number window with the item being sold, the maximum number the party can sell (usually however many they have on hand) and the item's selling price. Then we match the number window's currency unit up with whatever the gold window is using, and show/activate the number window. Finally, we set the item in the status window to the sale item and show that window too.

Scene_Shop.prototype.onSellCancel = function() {
    this._sellWindow.deselect();
    this._categoryWindow.activate();
    this._statusWindow.setItem(null);
    this._helpWindow.clear();
};


onSellCancel is the function we bound to the 'cancel' handler of the sell window. We deselect the sell window, activate the category window, set the item in the status window to null, and clear the help window.

Scene_Shop.prototype.onNumberOk = function() {
    SoundManager.playShop();
    switch (this._commandWindow.currentSymbol()) {
    case 'buy':
        this.doBuy(this._numberWindow.number());
        break;
    case 'sell':
        this.doSell(this._numberWindow.number());
        break;
    }
    this.endNumberInput();
    this._goldWindow.refresh();
    this._statusWindow.refresh();
};


onNumberOk is the function we bound to the 'ok' handler of the number window. We play the 'Shop' sound effect from the database, then have a switch statement against the current symbol in the command window. If it's 'buy' we call doBuy with the quantity from the number window. If it's 'sell' we call doSell with that number instead. After the switch, we end number input and refresh the gold/status windows.

Scene_Shop.prototype.onNumberCancel = function() {
    SoundManager.playCancel();
    this.endNumberInput();
};


onNumberCancel is the function we bound to the 'cancel' handler of the number window. We play the 'Cancel' sound effect from the database then end number input.

Scene_Shop.prototype.doBuy = function(number) {
    $gameParty.loseGold(number * this.buyingPrice());
    $gameParty.gainItem(this._item, number);
};


doBuy is the function called when the player confirms in the number window while the 'buy' command is selected. The party loses an amount of gold equal to the number being bought multiplied by the item's buy price, then gains that number of the chosen item.

Scene_Shop.prototype.doSell = function(number) {
    $gameParty.gainGold(number * this.sellingPrice());
    $gameParty.loseItem(this._item, number);
};


doSell is the function called when the player confirms in the number window while the 'sell' command is selected. The party gains an amount of gold equal to the number being sold multiplied by the item's sell price, then loses that number of the chosen item.

Scene_Shop.prototype.endNumberInput = function() {
    this._numberWindow.hide();
    switch (this._commandWindow.currentSymbol()) {
    case 'buy':
        this.activateBuyWindow();
        break;
    case 'sell':
        this.activateSellWindow();
        break;
    }
};


In the function to end number input, we hide the number window and then have a switch statement against the command window's current symbol. If it's 'buy' we call activateBuyWindow, and if it's 'sell' we call activateSellWindow. This ensures that when we "cancel" the number input, it returns us to the appropriate mode of the shop.

Scene_Shop.prototype.maxBuy = function() {
    var max = $gameParty.maxItems(this._item) - $gameParty.numItems(this._item);
    var price = this.buyingPrice();
    if (price > 0) {
        return Math.min(max, Math.floor(this.money() / price));
    } else {
        return max;
    }
};


In the function to determine the maximum number of an item the party can purchase, we set max to the result of calling the party's maxItems function for the given item (which is hardcoded as 99 by default) minus the number of that item the party currently has. price is set to the buying price from the scene, and then if the buy price is greater than 0 we return the minimum value between the maximum and the party's current money divided by the price of the item (rounded down). If the price is not greater than 0, we just return max. This ensures that the party is only able to buy as many of an item as they can afford or has room for.

Scene_Shop.prototype.maxSell = function() {
    return $gameParty.numItems(this._item);
};


The function to determine the maximum number of an item the party can sell, we return the number of that item held by the party.

Scene_Shop.prototype.money = function() {
    return this._goldWindow.value();
};


The function to determine how much money the party has simply returns the value in the gold window.

Scene_Shop.prototype.currencyUnit = function() {
    return this._goldWindow.currencyUnit();
};


Likewise with the currency unit, it's also determined by whatever the gold window is using.

Scene_Shop.prototype.buyingPrice = function() {
    return this._buyWindow.price(this._item);
};


The buying price for the scene is returned as the buy window's price for the chosen item.

Scene_Shop.prototype.sellingPrice = function() {
    return Math.floor(this._item.price / 2);
};


And the selling price for the scene is returned as half the chosen item's price rounded down.

We've covered a fair few classes now so I'll leave it there for part 5. There are four classes left to do but one of them is the behemoth that is Scene_Battle so it seems like a good breakpoint. After this we'll finish off rpg_scenes.js and will be able to move on to the next file!

I know that there are a fair number of people who read these, but if it's not too much to ask could I request that if you do you leave me a little comment with your impressions/thoughts on the series? I love reading comments and it helps me to feel like this whole thing is worth doing. I'd also like suggestions for which file to look at after scenes; currently I'm leaning towards rpg_objects.js but if enough people want something else I'll change my plans.

Until next time!

* episode does not actually contain action.