Writing RPGChain Quests

We have a standardized quest format available that you can use to construct your own engaging narratives and challenges. This not only provides a fun and unique way for our community to engage with RPGChain, but also helps to continually enrich the gaming experience for everyone.

RPGChain Quest Template Format

Each RPGChain quest points to a "quest template" configuration and set of markdown files. To better view this, let's look at a quest template called "recover-item". The following files would be listed in a directory similarly named "recover-item":

  • config.json

  • /markdown/INDEX.md

  • /markdown/TRAVEL.md

  • /markdown/ENTER_ITEM_LOCATION.md

  • /markdown/PUZZLE.md

  • /markdown/PUZZLE_SUCCESS.md

  • /markdown/PUZZLE_FAIL.md

  • ...

You'll see the directory list is fairly simple. A simple configuration file, followed by a series of markdown files which contain the content for each page of your story. Let's take a look at the heard of your quest. The quest template config.json file:

```json
{
    "variables": [
        "town",
        "giver",
        "item",
        "destination",
        "puzzle",
        "treasure",
        "enemy",
        "trap",
        "boss"
    ],
    "rolls": [
        {
            "dc": "10",
            "key": "TRAP",
            "label": "Rolling to avoid the trap",
            "actionSuccess": "page:TRAP_SUCCESS",
            "actionFail": "page:TRAP_FAIL"
        },
        {
            "dc": "6",
            "key": "ENEMY_ATTACK",
            "label": "Rolling to attack the enemy",
            "actionSuccess": "page:ENEMY_ATTACK_SUCCESS",
            "actionFail": "page:ENEMY_ATTACK_FAIL"
        },
        {
            "dcParent": "8",
            "key": "ENEMY_ATTACK_2",
            "label": "Rolling to attack the enemy",
            "actionSuccess": "page:ENEMY_ATTACK_2_SUCCESS",
            "actionFail": "page:ENEMY_ATTACK_2_FAIL"
        },
        {
            "dcParent": "12",
            "key": "BOSS_ATTACK",
            "label": "Rolling to attack the enemy",
            "actionSuccess": "page:BOSS_ATTACK_SUCCESS",
            "actionFail": "page:BOSS_ATTACK_FAIL"
        },
        {
            "dcParent": "10",
            "key": "BOSS_ATTACK_2",
            "label": "Rolling to attack the enemy",
            "actionSuccess": "page:BOSS_ATTACK_2_SUCCESS",
            "actionFail": "page:BOSS_ATTACK_2_FAIL"
        }
    ],
    "pages": [
        {
            "key": "INDEX",
            "image": "[town.image]",
            "options": [
                {"action":"page:TRAVEL","label": "I will recover this item for you"}
            ]
        },
        {
            "key": "TRAVEL",
            "image": "[giver.image]",
            "options": [
                {"action":"page:ENTER_ITEM_LOCATION","label": "Enter [ITEM_LOCATION.NAME]"}
            ]
        },
        {
            "key": "ENTER_ITEM_LOCATION",
            "image": "[destination.image]",
            "options": [
                {"action":"page:PUZZLE","label": "Head towards [puzzle.room_hint]"},
                {"action":"page:ENEMY","label": "Continue towards [side_enemy.room_hint]"}
            ]
        },
        {
            "key": "PUZZLE",
            "image": "[puzzle.image]",
            "options": [
                {"action":"page:PUZZLE_FAIL","label": "[puzzle.option_invalid_1]"},
                {"action":"page:PUZZLE_FAIL","label": "[puzzle.option_invalid_2]"},
                {"action":"page:PUZZLE_SUCCESS","label": "[puzzle.option_valid]"},
                {"action":"page:ENEMY","label": "Return to the previous room and take the other path"}
            ]
        },
        {
            "key": "PUZZLE_SUCCESS",
            "image": "[puzzle.image]",
            "options": [
                {"action":"page:TRAP","label": "Continue ahead"},
                {"action":"page:ENEMY","label": "Return to the previous room and take the other path"}
            ],
            "rewards": [
                "[treasure.key]"
            ]
        },
        {
            "key": "PUZZLE_FAIL",
            "image": "[puzzle.image]",
            "options": [
                {"action":"page:ENEMY","label": "Return to the previous room and take the other path"}
            ]
        },
        {
            "key": "ENEMY",
            "image": "[side_enemy.image]",
            "options": [
                {"action":"roll:ENEMY_ATTACK","label": "Attack!"}
            ]
        },
        {
            "key": "ENEMY_ATTACK_SUCCESS",
            "image": "[SIDE_ENEMY.IMAGE]",
            "options": [
                {"action":"page:TRAP","label": "Continue forward...carefully"}
            ],
            "displayRolls": ["ENEMY_ATTACK"],
            "xp": 50
        },
        {
            "key": "ENEMY_ATTACK_FAIL",
            "image": "[SIDE_ENEMY.IMAGE]",
            "options": [
                {"action":"roll:ENEMY_ATTACK_2","label": "Attack again!"}
            ],
            "displayRolls": ["ENEMY_ATTACK"]
        },
        {
            "key": "ENEMY_ATTACK_2_SUCCESS",
            "image": "[SIDE_ENEMY.IMAGE]",
            "options": [
                {"action":"page:TRAP","label": "Continue forward"}
            ],
            "displayRolls": ["ENEMY_ATTACK_2"],
            "xp": 25
        },
        {
            "key": "ENEMY_ATTACK_2_FAIL",
            "image": "[SIDE_ENEMY.IMAGE]",
            "options": [],
            "displayRolls": ["ENEMY_ATTACK_2"],
            "completionStatus": "FAILED"
        },
        {
            "key": "TRAP",
            "image": "[TRAP.IMAGE]",
            "options": [
                {"action":"roll:TRAP","label": "Attempt to avoid trap"}
            ]
        },
        {
            "key": "TRAP_SUCCESS",
            "image": "[TRAP.IMAGE]",
            "options": [
                {"action":"page:BOSS","label": "Continue Ahead"}
            ],
            "displayRolls": ["TRAP"],
            "xp": 25
        },
        {
            "key": "TRAP_FAIL",
            "image": "[TRAP.IMAGE]",
            "options": [
                {"action":"page:BOSS","label": "Continue Ahead"}
            ],
            "displayRolls": ["TRAP"]
        },
        {
            "key": "BOSS",
            "image": "[MAIN_ENEMY.IMAGE]",
            "options": [
                {"action":"roll:BOSS_ATTACK","label": "Attack!"}
            ]
        },
        {
            "key": "BOSS_ATTACK_SUCCESS",
            "image": "[MAIN_ENEMY.IMAGE]",
            "options": [
                {"action":"page:FIND_ITEM","label": "Keep moving"}
            ],
            "displayRolls": ["BOSS_ATTACK"],
            "xp": 100
        },
        {
            "key": "BOSS_ATTACK_FAIL",
            "image": "[MAIN_ENEMY.IMAGE]",
            "options": [
                {"action":"roll:BOSS_ATTACK_2","label": "Attack again!"}
            ],
            "displayRolls": ["BOSS_ATTACK"]
        },
        {
            "key": "BOSS_ATTACK_2_SUCCESS",
            "image": "[MAIN_ENEMY.IMAGE]",
            "options": [
                {"action":"page:FIND_ITEM","label": "Keep moving forward"}
            ],
            "displayRolls": ["BOSS_ATTACK_2"],
            "xp": 50
        },
        {
            "key": "BOSS_ATTACK_2_FAIL",
            "image": "[MAIN_ENEMY.IMAGE]",
            "options": [],
            "displayRolls": ["BOSS_ATTACK_2"],
            "completionStatus": "FAILED"
        },
        {
            "key": "FIND_ITEM",
            "image": "[ITEM.IMAGE]",
            "options": [
                {"action":"page:DELIVER","label": "Return to [ITEM_LOCATION.NAME]"}
            ]
        },
        {
            "key": "DELIVER",
            "image": "[ITEM.IMAGE]",
            "options": [],
            "completionStatus": "SUCCESS"
        }
    ]
}
```

While this file is large, it is generally fairly simple when broken down into its various parts:

  • variables: This optional section is simply an array of the variables our story will use. More details on these variables are defined further below, but allow our quest template to be re-used multiple times. Perhaps you want to have the same quest but given by a different person, or fighting a different enemy etc.

  • rolls: Here, all rolls that might take place in our quest are defined. Do you want the user to click a button and roll to see if they succeed or fail in opening a chest? Or fighting an enemy? Each roll will be defined with a DC (this number the user must roll higher than to succeed out of 20). On a success, they will trigger the actionSuccess or on fail trigger actionFail. These will likely push the user to a success or fail page

  • pages: All pages in your story are defined here.

    • key: Each page is defined with a "key", which is used in both the name of the markdown file this page relates to, as well as in other options when we tell which page to point to.

    • image: The image parameter can be a variable [item.image] or the full url to your own image. Each page has a featured image the user sees as they navigate your story.

    • options: This array of choices show on the bottom of your page, allowing the user to click a button to go to the next page, or make them choose between a set of actions, leading them in different paths. An option can take the form of a page (page:TRAVEL) to send them to the TRAVEL page, or it can make them roll dice (roll:TRAP).

    • completionStatus: If this page is the end of your story, you will need to set completionStatus to either "SUCCESS" or "FAILED" to indicate how the user finished the adventure

As mentioned, each page will have a corresponding markdown/[PAGE KEY].md file, which will look something like this:

You step forward into the next room as a loud locking sound is heard from behind you. You're trapped in here.

A [boss.name] lingers nearby. It seems ready to fight.

Each of these files can use available variables to allow multiple quests to be created from a single quest-template.

Quest Format

With a quest-template created, a quest file can now be created. Quest files are much simpler json files which point to a template and have specific details about this single quest. Here is an example named "recover-the-golden-apple.json":

```json
{
    "icon": "ankh",
    "name": "Recover the Golden Apple",
    "template": "recover-item",
    "description": "Assist the town holy man in finding his lost treasure",
    "image": "locations/gritch-church-inside.png",
    "variables": {
        "town": "cloverdale",
        "giver": "elroy-gritch",
        "item": "golden-apple",
        "destination":"gritch-church",
        "puzzle": "number-puzzle",
        "treasure":"ankh",
        "enemy":"snake",
        "trap":"rope-trap",
        "boss":"ghost"
    },
    "published_at": "2025-03-06 00:00:00",
    "playable_until": "2050-01-01 00:00:00"
}
```

A quest file defines the title and description of the story, the status of its playability, along with any variables from the RPGChain world that it might pull in.

Available Variables and World

Quest variables are optional but allow a single quest template to be played an almost infinite amount of times with changing features.

RPGChain keeps an ever-growing world full of people, items, and enemies available so new quests can be generated from templates at will.

Below is a list of available variables you can use in your quest:

[town.name], [town.description], [town.image]

[giver.name], [giver.nameShort], [giver.description], 
[giver.image], [giver.gender], [giver.occupation], [giver.race], 
[giver.greeting], [giver.pronounObject], [giver.pronounSubject],
[giver.pronounPossessive], [giver.acceptanceResponse], [giver.completionResponse]

[enemy.image], [enemy.name], [enemy.nameAlt], [enemy.roomHint]

[boss.image], [boss.name], [boss.nameAlt], [boss.roomHint]

[item.name], [item.nameAlt], [item.level], [item.image]

[treasure.name], [treasure.nameAlt], [treasure.level], [treasure.image]

[destination.name], [destination.description], [destination.image]

[puzzle.roomHint], [puzzle.hint], [puzzle.description], [puzzle.image], 
[puzzle.failDescription], [puzzle.successDescription], [puzzle.optionValid],
[puzzle.optionInvalid1], [puzzle.optionInvalid2]

[trap.name], [trap.image], [trap.introductionDescription], 
[trap.successDescription], [trap.failDescription]

We will soon be migrating our world files to a public github repository so you can easily view the growing list. Until then, here are a few examples:

Towns (cloverdale)

```json
{
    "name": "Cloverdale",
    "description": "Cloverdale is a small, idyllic town nestled in the rolling hills of the countryside. The town is known for its lush green pastures, bountiful crops, and friendly inhabitants.",
    "image": "locations/cloverdale.png"
}
```

Givers (beverly-hotfire)

```json
{
    "name": "Beverly Hotfire",
    "nameShort": "Mrs. Hotfire",
    "description": "She has cropped, wavy, auburn hair and golden eyes. You notice she is branded as a felon on her back.",
    "image": "people/beverly-hotfire.png",
    "gender": "Female",
    "occupation": "InnKeeper",
    "race": "Human",
    "greeting": "Good to see ya!",
    "acceptanceResponse": "Wow it means the world that you would do this for me.",
    "completionResponse": "Wow, I didn't know you had it in you! Impressive."
}
```

Enemies / Bosses (giant-rat)

```json
{
    "name": "Giant Rat",
    "nameAlt": "Gross Big Pest",
    "level": 0,
    "image": "enemies/giant-rat.png",
    "roomHint": "a large trail of feces"
}
```

Item (golden-chicken-statue)

```json
{
    "name": "Golden Chicken Statue",
    "nameAlt": "Statue",
    "level": 5,
    "image": "items/golden-chicken-statue.png"
}
```

Treasure (ale)

```json
{
    "name": "Ale",
    "description": "A delicious beverage in a glass mug",
    "image": "items/ale-1.png",
    "badge": "badges/ale-1.png"
}
```

Destination (hudson-mines)

// Some code```json
{
    "name": "Hudson Mines",
    "description": "Workers have left this mine a long time ago. Inside, the air is dry and thick webbing coats the walls.",
    "image": "locations/hudson-mines.png"
}
```

Puzzle (fibonacci)

```json
{
    "roomHint": "the sound of falling pebbles",
    "hint": "an old stone, which simply says 'FI', some remaining letters may have been broken off",
    "description": "A large marble desk holds square tiles of numbers. \n\n At the top of the desk, two numbers have already been placed. On the left, the number '610'. On the right, '1597'. In the middle, a hole is open for an additional tile. \n\n Or maybe it would be best to not mess with this?",
    "failDescription": "The tiles freeze up, you seem to not be able to remove the middle tile anymore. Nothing else appears to happen.",
    "successDescription": "The tiles freeze up, you seem to not be able to remove the middle tile anymore. A loud metal 'unlock' sound is heard on the base of the stone.\n\n A small door, slides open.",
    "validOption": "Place the tile labeled: 987",
    "invalidOptions": [
        "Place the tile labeled: 1123",
        "Place the tile labeled: 377"
    ],
    "image": "puzzles/fibonacci.png"
}
```

Trap (arrow-trap)

```json
{
    "name": "Arrow Trap",
    "introductionDescription": "The rancid smell assails, and you find yourself encapsulated in a dead zone. The place is punctuated with dead bodies. On the walls, there’s something, be wary of it!",
    "successDescription": "You were able to dodge the impaling arrows.",
    "failDescription": "Unable to dodge the impaling arrow, your brace while removing the sharp blade from the side of your hip. The wound will heal, but this has certainly slowed you down.",
    "image": "traps/arrow-1.png"
}

```

Have some custom world items, locations, or people you'd like to add? Send them to us with your quest and we'll add them to the RPGChain world!

Last updated