itch.io is community of indie game creators and players

Devlogs

Adding content to Short Rest

Short Rest
A browser game made in HTML5

Some folks have shown interest in how this game works, so I thought I'd do a quick writeup of how you could go about adding content to it! Almost all of the ingame content is loaded at runtime from a couple text files, which makes adding things pretty simple once you know the basics.

To start, you'll need a downloaded copy of the game. The easiest ways to download it are to use the itch app, or to clone the GitHub repo and build it from source. Building it from source has some benefits but requires more setup, so let's stick with the itch version for now.

Once downloaded in the app, select the gear icon, then "Manage", then "Open folder in explorer" to find the files:

We can ignore most of these: Everything we need to modify is under /assets.

The relevant files here are:

  • textures/: A folder with all the in-game images
  • assets.txt: A list of all the files loaded by the game
  • cards.txt, obstacles.txt, levels.txt: All of the cards, enemies/encounters, and level generation (these are labelled .txt, but actually contain javascript)

Adding a party member

To add a custom hero to the party, we'll first need to draw them. For demonstration, I'm just going to grab the existing peach character from the intro and make a couple quick edits so they're facing the right direction and have a weapon:

...good enough.

I'm going to name this peach_hero.png, and put it under assets/textures/. To let the game load the new image, we add a line to assets/assets.txt:

textures/cards/Priest.png
textures/cards/Rogue.png
+ textures/peach_hero.png

Next, we need to add them to the party. The party is created in assets/levels.txt, near the top of the return. I'm going to put them in after the apple rogue:

            scene.addParty({
                name: 'Rogue',
                spr: 'apple',
                maxHealth: 2,
                damage: 2,
            });
+            scene.addParty({
+                name: 'Peach',
+                spr: 'peach_hero',
+                maxHealth: 4,
+                damage: 99,
+            });

Now when we start the game...

...there she is!

We've added a custom hero, so let's make a new card to go with them next.

Adding a card

All of the cards are defined in assets/cards.txt. Since I drew the hero with a spear, let's add a card that references that:

        'Heal Knight': heal('Knight'),
        'Heal Priest': heal('Priest'),
+        Pierce: {
+            sprite: 'Slash',
+            description: 'Peach does 1 damage to two enemies',
+            canPlay(scene) {
+                return scene.enemy && scene.alive('Peach');
+            },
+            effect(scene) {
+                scene.obstacles[0].damage(1);
+                if (scene.obstacles[1]) {
+                    scene.obstacles[1].damage(1);
+                }
+                scene.sfx('sfx1');
+            },
+        },

There's a few things to note here:

  • sprite is setting the icon for the card
  • description is setting the tooltip text shown on hover
  • canPlay is preventing the player from using the card if our hero isn't alive to use it, or if there's no enemy for it to target
  • effect is implementing the card: it damages the first enemy, also damages the second enemy (if there is one), and plays a sound effect to go with it.

To get the card ingame, I'm just going to give it to the player in levels.txt right after the party is created:

            scene.addParty({
                name: 'Peach',
                spr: 'peach_hero',
                maxHealth: 4,
                damage: 99,
            });
+            scene.addCard('Pierce');

Now when we restart the game...

...our new card will be available to use in the intro!

If we wanted to give our card a custom icon instead of re-using one of the existing ones, we could add a new asset and replace the sprite with its name.

So what about enemies?

Adding an enemy

Like the custom hero, we're going to want add a new drawing for this, and add it to assets/textures and assets/assets.txt.

textures/cards/Rogue.png
textures/peach_hero.png
+ textures/eggnemy.png

Next we'll add the enemy to obstacles.txt:

        bat: {
            name: 'Eyebat',
            health: 1,
            damage: 1,
        },
+        eggnemy: {
+            name: 'Eggnemy',
+            health: 2,
+            damage: 1,
+            start(scene) {
+                scene.log('"Let\'s get cracking!"');
+            },
+            interact(scene) {
+                scene.log('*crack*');
+            },
+            end(scene) {
+                scene.log('"All I wanted was to be an omelette..."');
+            },
+        },

This definition looks a bit like the party member, but is a bit more involved: start, interact, and end are functions that run when the player encounters the enemy, when the enemy is hit with "Advance", and when the enemy is defeated.

I've just made it add some flavour text for the action log, but this is where all of the encounter logic lives. Try checking out some of the other obstacles for more complex examples!

If we want this obstacle to show up ingame, we'll need to modify levels.txt again. I'm going to replace the list of basic enemies with this new one so we're guaranteed to run into it in the first level:

-    const basic = [['bat'], ['rat_small']];
+    const basic = [['eggnemy']];

Now we can restart the game, embark into the dungeon...

...and fight our enemy!

You might notice when going through the camp here that the peach we added earlier doesn't have a card icon: You'll need to edit the "Reorder Party" card in cards.txt to add one.

More info

This covered all the basics, but cards.txt, obstacles.txt, and levels.txt all have comments at the top explaining their formats, and cards.txt also lists out a bunch of the scene functions that handle more complex effects and interactions. Some of the more important bits to note:

  • obstacles.txt includes an array of cards near the top called cardsAll: loot is pulled from this list, so make sure to add your cards here if you want them to show up in chests!
  • levels.txt includes multiple different "pools" near the top which group obstacles by type for the level generation (e.g. basic enemies, restore points, minibosses). You can customize the level generation itself, but the easiest way to make obstacles show up ingame is to add them to the relevant pool.
  • The ingame start and options menus are implemented using cards, and are all defined near the top of cards.txt just like any other cards would be.

Feel free to reach out if you try playing around with the files and have any questions!

Read comments (1)