In which I object.

  • Trihan
  • 04/29/2017 11:08 PM
Hello sports fans! If you're one of my Patreon patrons, welcome to your advance copy of the new

Jump into Javascript

otherwise, sucks to be you! Other people had this a week ago, but now you get to read it too.

As I said in the last episode, I was thinking of doing rpg_objects.js next unless I got requests in the comments for something else. Nobody really commented, so rpg_objects.js it is!

As with the previous episodes, I won't bother covering the instantiation functions or functions that are common to most/all classes and don't have anything new.

This is the class for temporary data that isn't saved when the game is.

Game_Temp.prototype.initialize = function() {
    this._isPlaytest = Utils.isOptionValid('test');
    this._commonEventId = 0;
    this._destinationX = null;
    this._destinationY = null;

The initialize function for Game_Temp sets a number of local variables. _isPlayTest is set to the result of calling the isOptionValid function of the Utils class, passing in the string 'test'. We'll cover Utils in detail when we finally get around to looking at rpg_core.js, but suffice to say this is how we check whether the game is in play test mode. _commonEventId is set to 0. _destinationX and _destinationY are set to null.

Game_Temp.prototype.isPlaytest = function() {
    return this._isPlaytest;

The isPlaytest function returns the value of _isPlaytest. As we've covered before, this is just an example of encapsulation providing an interface for external classes to check the playtest status without having to expose the internal local variable to do so.

Game_Temp.prototype.reserveCommonEvent = function(commonEventId) {
    this._commonEventId = commonEventId;

The reserveCommonEvent function reserves a common event which will be executed on the map. It takes commonEventId as a parameter and simply sets the local _commonEventId variable to the parameter value.

Game_Temp.prototype.clearCommonEvent = function() {
    this._commonEventId = 0;

clearCommonEvent sets the _commonEventId variable to 0, clearing any currently reserved common events.

Game_Temp.prototype.isCommonEventReserved = function() {
    return this._commonEventId > 0;

isCommonEventReserved checks whether a common event is reserved. Returns true if _commonEventId is greater than 0, and false otherwise.

Game_Temp.prototype.reservedCommonEvent = function() {
    return $dataCommonEvents[this._commonEventId];

reservedCommonEvent gets the common event that has been reserved. It returns the element of $dataCommonEvents located at the index of _commonEventId's value.

Game_Temp.prototype.setDestination = function(x, y) {
    this._destinationX = x;
    this._destinationY = y;

setDestination is pretty self-explanatory, and takes x/y as parameters. It simply sets the _destinationX and _destinationY variables to the parameter values.

Game_Temp.prototype.clearDestination = function() {
    this._destinationX = null;
    this._destinationY = null;

clearDestination clears the destination by setting _destinationX and _destinationY to null.

Game_Temp.prototype.isDestinationValid = function() {
    return this._destinationX !== null;

isDestinationValid checks whether the destination is valid. All it does is return true if _destinationX is not null, and false otherwise.

Game_Temp.prototype.destinationX = function() {
    return this._destinationX;

destinationX is another wrapper that returns the internal _destinationX variable.

Game_Temp.prototype.destinationY = function() {
    return this._destinationY;

Same thing but for _destinationY.

This class contains system data like the enabled state of menu options.

Game_System.prototype.initialize = function() {
    this._saveEnabled = true;
    this._menuEnabled = true;
    this._encounterEnabled = true;
    this._formationEnabled = true;
    this._battleCount = 0;
    this._winCount = 0;
    this._escapeCount = 0;
    this._saveCount = 0;
    this._versionId = 0;
    this._framesOnSave = 0;
    this._bgmOnSave = null;
    this._bgsOnSave = null;
    this._windowTone = null;
    this._battleBgm = null;
    this._victoryMe = null;
    this._defeatMe = null;
    this._savedBgm = null;
    this._walkingBgm = null;

The initialize method sets a pretty crazy number of local variables. _saveEnabled, _menuEnabled, _encounterEnabled and _formationEnabled are set to true as they're booleans; _battleCount, _winCount, _escapeCount, _saveCount, _versionId and _framesOnSave are set to 0 as they're integers; and _bgmOnSave, _bgsOnSave, _windowTone, _battleBgm, _victoryMe, _defeatMe, _savedBgm and _walkingBgm are set to null as they usually contain objects.

Game_System.prototype.isJapanese = function() {
    return $dataSystem.locale.match(/^ja/);

Game_System.prototype.isChinese = function() {
    return $dataSystem.locale.match(/^zh/);

Game_System.prototype.isKorean = function() {
    return $dataSystem.locale.match(/^ko/);

Game_System.prototype.isCJK = function() {
    return $dataSystem.locale.match(/^(ja|zh|ko)/);

Game_System.prototype.isRussian = function() {
    return $dataSystem.locale.match(/^ru/);

I've included these in a group as they're all checking whether the game's locale is a particular country. This allows developers to check whether the local is Japanese, Chinese, Korean, any one of those three, or Russian.

Been a while since we had a new concept! The behemoth that is regex is far too large in scope for what we're doing here, but I'll give you a quick overview.

Regular expressions are basically a way to check strings for a pattern rather than something specific. This is especially useful when you don't know ahead of time what the string will contain, but don't want to have an if statement for every possible combination. .match is a function you can call on a string which takes a regex pattern as a parameter. You can tell it's a regex pattern because it's enclosed in forward slashes. The ^ will match "the start of the string" so in isJapanese for example, we're checking whether the locale string begins with "ja". If we have a number of strings enclosed in brackets and separated by pipes, it will match any of those combinations. So in isCJK, match will return true if the locale string starts with "ja" OR "zh" OR "ko".

Game_System.prototype.isSideView = function() {
    return $dataSystem.optSideView;

isSideView checks whether the game is using a side view battle system. Returns true if the optSideView property of $dataSystem is true, false otherwise (it will be true if the checkbox in the database is ticked).

Game_System.prototype.isSaveEnabled = function() {
    return this._saveEnabled;

isSaveEnabled checks whether the game can be manually saved; it's a wrapper for returning the value of _saveEnabled.

Game_System.prototype.disableSave = function() {
    this._saveEnabled = false;

disableSave prevents the player from saving the game by setting _saveEnabled to false.

Game_System.prototype.enableSave = function() {
    this._saveEnabled = true;

enableSave allows the player to save the game by setting _saveEnabled to true.

Game_System.prototype.isMenuEnabled = function() {
    return this._menuEnabled;

isMenuEnabled checks whether the player can access the game menu; it's a wrapper for returning the value of _menuEnabled.

Game_System.prototype.disableMenu = function() {
    this._menuEnabled = false;

disableMenu prevents the player from accessing the game menu by setting _menuEnabled to false.

Game_System.prototype.enableMenu = function() {
    this._menuEnabled = true;

enableMenu allows the player to access the game menu by setting _menuEnabled to true.

Game_System.prototype.isEncounterEnabled = function() {
    return this._encounterEnabled;

isEncounterEnabled checks whether the player can get into a random encounter by returning the value of _encounterEnabled.

Game_System.prototype.disableEncounter = function() {
    this._encounterEnabled = false;

disableEncounter prevents the player from getting into random encounters by setting _encounterEnabled to false.

Game_System.prototype.enableEncounter = function() {
    this._encounterEnabled = true;

enableEncounter allows the player to get into random encounters by setting _encounterEnabled to true.

Game_System.prototype.isFormationEnabled = function() {
    return this._formationEnabled;

isFormationEnabled checks whether the player can change the party formation by returning the value of _formationEnabled.

Game_System.prototype.disableFormation = function() {
    this._formationEnabled = false;

disableFormation prevents the player from changing party formation by setting _formationEnabled to false.

Game_System.prototype.enableFormation = function() {
    this._formationEnabled = true;

enableFormation allows the player to change party formation by setting _formationEnabled to true.

Game_System.prototype.battleCount = function() {
    return this._battleCount;

battleCount gets how many battles the player has fought by returning the value of _battleCount.

Game_System.prototype.winCount = function() {
    return this._winCount;

winCount gets how many battles the player has won by returning the value of _winCount.

Game_System.prototype.escapeCount = function() {
    return this._escapeCount;

escapeCount gets how many battles the player has run from by returning the value of _escapeCount.

Game_System.prototype.saveCount = function() {
    return this._saveCount;

saveCount gets how many times the player has saved the game by returning the value of _saveCount.

Game_System.prototype.versionId = function() {
    return this._versionId;

versionId gets the version ID of the game by returning _versionId. The value is auto-generated every time the project is saved.

Game_System.prototype.windowTone = function() {
    return this._windowTone || $dataSystem.windowTone;

windowTone gets the tone used for windows. Returns the _windowTone value if it's not null, and $dataSystem.windowTone otherwise, which gets the tone set in the database.

Game_System.prototype.setWindowTone = function(value) {
    this._windowTone = value;

setWindowTone sets the tone used for windows, taking value as a parameter. Sets the _windowTone variable to the parameter value. This will usually be an array consisting of the red, green, blue and alpha values of the tone. The alpha value doesn't seem to actually do anything, as it makes absolutely no difference to the window tone regardless of the value passed in.

Game_System.prototype.battleBgm = function() {
    return this._battleBgm || $dataSystem.battleBgm;

battleBgm gets the BGM set for battles by returning _battleBgm if it is not null and $dataSystem.battleBgm otherwise, which gets the BGM set in the database.

Game_System.prototype.setBattleBgm = function(value) {
    this._battleBgm = value;

setBattleBgm sets the BGM used for battles, taking value as a parameter. Sets the _battleBgm variable to the parameter value. This will be an object with "name", "pan", "pitch" and "volume" keys.

Game_System.prototype.victoryMe = function() {
    return this._victoryMe || $dataSystem.victoryMe;

victoryMe gets the ME set for victory by returning _victoryMe if it is not null and $dataSystem.victoryMe otherwise, which gets the ME set in the database.

Game_System.prototype.setVictoryMe = function(value) {
    this._victoryMe = value;

setVictoryMe sets the ME used for victory, taking value as a parameter. Sets the _victoryMe variable to the parameter value. This will be an object with the same keys as those in setBattleBgm.

Game_System.prototype.defeatMe = function() {
    return this._defeatMe || $dataSystem.defeatMe;

This is the same thing as victoryMe only for the defeat ME.

Game_System.prototype.setDefeatMe = function(value) {
    this._defeatMe = value;

This is the same thing as setVictoryMe only for the defeat ME.

Game_System.prototype.onBattleStart = function() {

onBattleStart is what's known as an "event" function, which is basically a function that exists to be called in response to a trigger. You can identify these in the core JS scripts because their names always begin with "on". In this case, the function is called when a battle begins. It adds 1 to _battleCount.

Game_System.prototype.onBattleWin = function() {

The same thing but called when the party wins a battle, and adds 1 to _winCount.

Game_System.prototype.onBattleEscape = function() {

The same thing but called when the party escapes a battle, and adds to to _escapeCount.

Game_System.prototype.onBeforeSave = function() {
    this._versionId = $dataSystem.versionId;
    this._framesOnSave = Graphics.frameCount;
    this._bgmOnSave = AudioManager.saveBgm();
    this._bgsOnSave = AudioManager.saveBgs();

onBeforeSave is called prior to the game being saved. It adds 1 to _saveCount, sets _versionId to $dataSystem.versionId, sets _framesOnSave to the number of frames that have elapsed since the game started, sets _bgmOnSave to the saved BGM in AudioManager, and sets _bgsOnSave to the saved BGS in AudioManager (we'll look more closely at this when we examing rpg_managers.js).

Game_System.prototype.onAfterLoad = function() {
    Graphics.frameCount = this._framesOnSave;

onAfterLoad is called following the loading of a saved game. It sets Graphics.frameCount to _framesOnSave, then plays the BGM and BGS stored in _bgmOnSave and _bgsOnSave.

Game_System.prototype.playtime = function() {
    return Math.floor(Graphics.frameCount / 60);

playtime gets the number of seconds the game has been running by returning the floor of Graphics.frameCount divided by 60. We divide by 60 because by default the game runs at 60 frames per second; if you ever change the FPS of the game, you'll have to change this value accordingly or the playtime won't line up.

Game_System.prototype.playtimeText = function() {
    var hour = Math.floor(this.playtime() / 60 / 60);
    var min = Math.floor(this.playtime() / 60) % 60;
    var sec = this.playtime() % 60;
    return hour.padZero(2) + ':' + min.padZero(2) + ':' + sec.padZero(2);

playtimeText determines the textual representation of the time played. It sets a temp variable called hour to the floor of the number of seconds played divided by 60 divided by 60, then a temp variable called min to the floor of seconds played divided by 60 MOD 60, and a temp variable called sec to seconds played MOD 60. Then we return a string consisting of hour padded with zeroes to 2 digits, a colon, min padded with zeroes to 2 digits, another colon, and sec padded with zeroes to 2 digits.

To better understand this, let's say that 271200 frames have elapsed. playtime() will be 271200 / 60 = 4520 seconds. hour will be Math.floor(4520 / 60 / 60) = 1.255 rounded to 1. min will be Math.floor(4520 / 60) % 60 = 75 % 60 = 15. sec will be 4520 % 60 = 20. So the returned string will be "01:15:20".

Game_System.prototype.saveBgm = function() {
    this._savedBgm = AudioManager.saveBgm();

saveBgm saves the currently-playing BGM to _savedBgm by calling the saveBgm function of AudioManager.

Game_System.prototype.replayBgm = function() {
    if (this._savedBgm) {

replayBgm replays the saved BGM. Calls the replayBgm function of AudioManager passing in _savedBgm, but only if it isn't null.

Game_System.prototype.saveWalkingBgm = function() {
    this._walkingBgm = AudioManager.saveBgm();

This is the same as saveBgm but sets _walkingBgm instead of _savedBgm.

Game_System.prototype.replayWalkingBgm = function() {
    if (this._walkingBgm) {

This is the same as replayBgm but replays _walkingBgm instead of _savedBgm.

This class handles the in-game timer.

Game_Timer.prototype.initialize = function() {
    this._frames = 0;
    this._working = false;

The initialize function of the timer sets _frames (the number of frames the timer will run for) to 0 and _working (a boolean determining whether the timer is running) to false.

Game_Timer.prototype.update = function(sceneActive) {
    if (sceneActive && this._working && this._frames > 0) {
        if (this._frames === 0) {

The frame update function takes one parameter, sceneActive, which is a boolean determining whether the scene is currently active.

If the scene is active AND _working is true AND _frames is greater than 0, the function decrements _frames by 1. Then if _frames is equal to 0, it calls the onExpire function.

Game_Timer.prototype.start = function(count) {
    this._frames = count;
    this._working = true;

start is the function which begins the timer, taking count as a parameter. It sets _frames to the parameter value, and _working to true.

Game_Timer.prototype.stop = function() {
    this._working = false;

stop is the function which ends the timer. It sets _working to false.

Game_Timer.prototype.isWorking = function() {
    return this._working;

isWorking is a function that gets whether the timer is running by returning the value of _working.

Game_Timer.prototype.seconds = function() {
    return Math.floor(this._frames / 60);

seconds is a function that gets the number of seconds left on the timer by returning the floor of _frames divided by 60 (again, because that's the number of frames per second the game runs at).

Game_Timer.prototype.onExpire = function() {

onExpire is the event function that gets called when _frames reaches 0 in the update function. All it does by default is call BattleManager.abort(), which is why if a timer is running in battle and reaches 0, the battle immediately ends.

This class handles the message window.

Game_Message.prototype.initialize = function() {

The initialize function for messages looks pretty simple at first glance, all it does is call its own clear function...

Game_Message.prototype.clear = function() {
    this._texts = [];
    this._choices = [];
    this._faceName = '';
    this._faceIndex = 0;
    this._background = 0;
    this._positionType = 2;
    this._choiceDefaultType = 0;
    this._choiceCancelType = 0;
    this._choiceBackground = 0;
    this._choicePositionType = 2;
    this._numInputVariableId = 0;
    this._numInputMaxDigits = 0;
    this._itemChoiceVariableId = 0;
    this._itemChoiceItypeId = 0;
    this._scrollMode = false;
    this._scrollSpeed = 2;
    this._scrollNoFast = false;
    this._choiceCallback = null;

Yeaaaaaaah. Okay, so this still isn't too complex. We're initialising two arrays, a string, 12 integers, two booleans, and one object. The ones that won't be so obvious are _background (0 is window, 1 is dim, 2 is transparent; it defaults to window), _positionType (0 is top, 1 is middle, 2 is bottom; it defaults to bottom), _choiceDefaultType (a positive value is the ID of the choice that will be considered default, or -1 if "none"), _choiceCancelType (a positive value is the ID of the choice that will act as cancel, -1 for "disallow" and -2 for "branch"), _choiceBackground (same as _background), and _choicePositionType (same as _positionType). _choiceCallback is slightly more interesting: it's essentially used to determine which branch of the event will be processed depending on the player's choice, and will eventually contain a function call.

Game_Message.prototype.choices = function() {
    return this._choices;

Game_Message.prototype.faceName = function() {
    return this._faceName;

Game_Message.prototype.faceIndex = function() {
    return this._faceIndex;

Game_Message.prototype.background = function() {
    return this._background;

Game_Message.prototype.positionType = function() {
    return this._positionType;

Game_Message.prototype.choiceDefaultType = function() {
    return this._choiceDefaultType;

Game_Message.prototype.choiceCancelType = function() {
    return this._choiceCancelType;

Game_Message.prototype.choiceBackground = function() {
    return this._choiceBackground;

Game_Message.prototype.choicePositionType = function() {
    return this._choicePositionType;

Game_Message.prototype.numInputVariableId = function() {
    return this._numInputVariableId;

Game_Message.prototype.numInputMaxDigits = function() {
    return this._numInputMaxDigits;

Game_Message.prototype.itemChoiceVariableId = function() {
    return this._itemChoiceVariableId;

Game_Message.prototype.itemChoiceItypeId = function() {
    return this._itemChoiceItypeId;

Game_Message.prototype.scrollMode = function() {
    return this._scrollMode;

Game_Message.prototype.scrollSpeed = function() {
    return this._scrollSpeed;

Game_Message.prototype.scrollNoFast = function() {
    return this._scrollNoFast;

All of these functions are just wrappers to return the corresponding local variables, nothing exciting.

Game_Message.prototype.add = function(text) {

The add function takes one parameter, text, and pushes it to the _texts array.

Game_Message.prototype.setFaceImage = function(faceName, faceIndex) {
    this._faceName = faceName;
    this._faceIndex = faceIndex;

Game_Message.prototype.setBackground = function(background) {
    this._background = background;

Game_Message.prototype.setPositionType = function(positionType) {
    this._positionType = positionType;

Game_Message.prototype.setChoices = function(choices, defaultType, cancelType) {
    this._choices = choices;
    this._choiceDefaultType = defaultType;
    this._choiceCancelType = cancelType;

Game_Message.prototype.setChoiceBackground = function(background) {
    this._choiceBackground = background;

Game_Message.prototype.setChoicePositionType = function(positionType) {
    this._choicePositionType = positionType;

Game_Message.prototype.setNumberInput = function(variableId, maxDigits) {
    this._numInputVariableId = variableId;
    this._numInputMaxDigits = maxDigits;

Game_Message.prototype.setItemChoice = function(variableId, itemType) {
    this._itemChoiceVariableId = variableId;
    this._itemChoiceItypeId = itemType;

Game_Message.prototype.setScroll = function(speed, noFast) {
    this._scrollMode = true;
    this._scrollSpeed = speed;
    this._scrollNoFast = noFast;

Game_Message.prototype.setChoiceCallback = function(callback) {
    this._choiceCallback = callback;

Here we have the setters for the various local variables. These should all be pretty self-explanatory by now.

Game_Message.prototype.onChoice = function(n) {
    if (this._choiceCallback) {
        this._choiceCallback = null;

The onChoice event function takes one parameter, n, which will be the ID of a choice. If _choiceCallback is not null, the function calls it passing in n, then sets _choiceCallback to null. This will process whatever code is contained in the choice branch before setting it back to null so that it won't run again.

Game_Message.prototype.hasText = function() {
    return this._texts.length > 0;

Game_Message.prototype.isChoice = function() {
    return this._choices.length > 0;

Game_Message.prototype.isNumberInput = function() {
    return this._numInputVariableId > 0;

Game_Message.prototype.isItemChoice = function() {
    return this._itemChoiceVariableId > 0;

These functions check whether their respective local variables have been changed from their defaults. hasText and isChoice check to see whether the arrays have more than 0 elements, while isNumberInput and isItemChoice check to see whether their variable values are greater than 0.

Game_Message.prototype.isBusy = function() {
    return (this.hasText() || this.isChoice() ||
            this.isNumberInput() || this.isItemChoice());

isBusy is a function that checks whether the message window is currently doing something. It'll return true if the message has text OR is displaying choices OR a number is being selected OR an item is being selected.

Game_Message.prototype.newPage = function() {
    if (this._texts.length > 0) {
        this._texts[this._texts.length - 1] += '\f';

newPage progresses the message to a new page, oddly enough. If the _texts array has more than 0 elements in it, it adds '\f' (line feed) to the end of the array.

Game_Message.prototype.allText = function() {
    return this._texts.reduce(function(previousValue, currentValue) {
        return previousValue + '\n' + currentValue;

The allText function gets the entire message to be displayed, by calling the reduce function on _texts.

reduce is a rather interesting function. It basically iterates through all elements of an array, applying a passed-in function to each one. In this case, it's being used to concatenate all lines in the array into one string.

The function passed in takes two parameters: a 'total' parameter, which in this case is called previousValue, and a 'current' parameter, which in this case is called currentValue. In the body of the passed-in function, each iteration will return previousValue, followed by '\n' (newline character), followed by currentValue. In the end, this will result in a single string containing all lines of text in the message separated by newline characters.

That's it for this week! It's a bit shorter than usual because I was already behind with the early access posts, but now that we're properly into the new release schedule they shouldn't be late again.

Until next time!