Posts

Building a Stat System in Monogatari

Monogatari while having several features right out the box, it still lacks an implementation of a Stat system, which you could use to create Dating Sims and RPG games, however it does have something, Monogatari is extremely extensible and adding a Stat System is fairly easy.

Edit: This Tutorial has been updated to match the Monogatari v1.4.1 features. (July 19, 2018)

Step 1: Add the stat Object

Monogatari ships with a variable reserved for custom storage, the storage variable will be found in the options.js file. Inside the storage object, we can put anything we want to save every time a player saves the game. By default it will look like this:

// Persistent Storage Variable

let storage = {
    player: {
        name: ""
    }
};

As we can see, there's already a property called player there, we'll use that property to save our stats. Since it's a date-sim, we might want to store stats like intelligence, love, attractiveness etc. To do so, let's create a property inside the player object for the stats and let's start them all in zero:

let storage = {
    player: {
        name: "",
        stats: {
            "intelligence": 0,
            "love": 0,
            "attractiveness": 0
        }
    }
}

Now we can access this from JavaScript and the stats will be saved with every saved game. What we need now is to be able to add or subtract points to those stats. To keep this simple, doing it by using functions might be the best option.

Step 2: Make our stats useful

When you first create a new Monogatari Project, there's already a custom Script, in it you can actually see the storage.player.Name property being used to store the name of the player:

let script = {
    // The game starts here.
    "Start": [
        "notify Welcome",
        {
            "Input": {
                "Text": "What is your name?",
                "Validation": function (input) {
                    return input.trim().length > 0;
                },
                "Save": function (input) {
                    storage.player.Name = input;
                    return true;
                },
                "Warning": "You must enter a name!"
            }
        },

        "h Hi {{player.Name}} Welcome to Monogatari!",

        {
            "Choice": {
                "Dialog": "h Have you already read some documentation?",
                "Yes": {
                    "Text": "Yes",
                    "Do": "jump Yes"
                },
                "No": {
                    "Text": "No",
                    "Do": "jump No"
                }
            }
        }
    ],

    "Yes": [

        "h That's awesome!",
        "h Then you are ready to go ahead and create an amazing Game!",
        "h I can't wait to see what story you'll tell!",
        "end"
    ],

    "No": [

        "h You can do it now.",

        "display message Help",

        "h Go ahead and create an amazing Game!",
        "h I can't wait to see what story you'll tell!",
        "end"
    ]
};

Let's modify the script to make use of our new stats:

let script = {
    // The game starts here.
    "Start": [
        "notify Welcome",
        {"Input": {
            "Text": "What is your name?",
            "Validation": function (input) {
                return input.trim ().length > 0;
            },
            "Save": function (input) {
                storage.player.name = input;
                return true;
            },
            "Warning": "You must enter a name!"
        }},
        "h Hi {{player.name}}, this demo is to demonstrate how to create a simple stat system",
        "h Currently you have {{player.stats.intelligence}} points of Intelligence but you seem far more intelligent, how about we add five points?",
        {"Function": {
            "Apply": function () {
                storage.player.stats.intelligence += 5;
                return true;
            },
            "Reverse": function () {
                storage.player.stats.intelligence -= 5;
                return true;
            }
        }},
        "h There you have it, you now have {{player.stats.intelligence}}  points of Intelligence",
        "end"
    ]
};

Now the script will ask for your name, show you the initial quantity of intelligence points you have and then add 5 points to it. The same can be done with all the other stats.

Step 3: Show the Stats

We now have modified the stats but currently there's no way the player can see how he's doing so let's add a screen for that. In order to do that, we need to add 3 things:

  1. The HTML code of our new screen
  2. A button to show and hide the stats
  3. The javascript code to make that button work

For the HTML part, we'll create a modal window but it really is up to you how you want your players to view the stats. Add the following code right above the data-ui='message' element:

<div data-component="modal" data-ui="stats" class="middle vertical align-center">
    <b>Stats</b>
    <span>Intelligence:</span>
    <meter value="0" max="10" data-stat="intelligence"></meter>
    <span>Love:</span>
    <meter value="0" max="10" data-stat="love"></meter>
    <span>Attractiveness:</span>
    <meter value="0" max="10" data-stat="attractiveness"></meter>
</div>

As you can see, by using meters the players will actually see a bar for each of their stats. Now let's add the button to the data-ui='quick-menu' element:

<span data-action="stats"><span class="fa fa-tasks" data-action="stats"></span> <span data-string="Stats" data-action="stats">Stats</span></span>

And finally inside the main.js file, we'll add a handler so that when the button is clicked, the modal is shown or hidden:

$_ready (function () {
    $_('[data-action="stats"]').click (function() {
        if ($_('[data-ui="stats"]').isVisible ()) {
            $_('[data-ui="stats"]').removeClass ('active');
        } else {
            $_('[data-ui="stats"]').addClass ('active');
        }
    });
});

Once you've done all this, you should be able to see the button, click it and the stats will be shown. However, after some playing will it, you'll notice something, the stat bars are not changing even when the stat is modified. The reason is simple, we are changing it's value in JavaScript but not in the HTML document however doing it with our current code that would involve repeating many unnecessary code. How about we create a function to modify the stats instead of doing it manually as we previously did? To do it, right above the declaration of the script variable in the script.js file place the following function:

function stat (stat, value) {
    storage.player.stats[stat] += value;
    $_(`[data-stat="${stat}"]`).value (storage.player.stats[stat]);
}

The function will take 2 parameters, the stat name and the quantity you want to add, once added we can modify our previous script code:

let script = {
    // The game starts here.
    "Start": [
        "notify Welcome",
        {"Input": {
            "Text": "What is your name?",
            "Validation": function (input) {
                return input.trim().length > 0;
            },
            "Save": function (input) {
                storage.player.name = input;
                return true;
            },
            "Warning": "You must enter a name!"
        }},
        "h Hi {{player.name}}, this demo is to demonstrate how to create a simple stat system",
        "h Currently you have {{player.stats.intelligence}} points of Intelligence but you seem far more intelligent, how about we add five points?",
        {"Function": {
            "Apply": function () {
                stat ("intelligence", 5);
                return true;
            },
            "Reverse": function () {
                stat ("intelligence", -5);
                return true;
            }
        }},
        "h There you have it, you now have {{player.stats.intelligence}} points of Intelligence",
        "end"
    ]
};

This way we'll be able to easily change the stats value both in JavaScript and the HTML bars.

Step 4: Changing choices

We've got now a fully functional stat system, the question now is how will we use it? Here are some options:

Step 5: Styling

Naturally, you'll need to style your meter bars and modal window in order to look pretty and match your game's style, just add some CSS and your game will be ready to amaze people!

Download

You can get the source code of this project here: Monogatari-Stat-System.zip