Adding A Custom Quest to Rance X

This tutorial will demonstrate how to add a custom quest to Rance X, complete with a map, events and battles.

Dumping the .ex file

Most of our work will be done by editing the file Rance10EX.ex. Before we can do anything, we need to dump this file to a text based format that can be edited. Run the following command to dump the file into a folder named “ex”:

alice ex dump -o ex --split Rance10EX.ex

Adding the mission

Open the file ex/6_クエスト情報.x. This is the list of all of the quests in the game, to which we will add an entry. Each row in this table consists of the following fields:

{
    int Id,                // an integer uniquely identifying the quest
    string 識別名,         // a string uniquely identifying the quest
    int 種別,              // ?
    string クエスト名,     // The name of the quest (as it's displayed to the user)
    string 説明1,         // The first line of quest explanation text
    string 説明2,         // The second line of quest explanation text
    string 説明3,         // The third line of quest explanation text
    string 説明4,         // The fourth line of quest explanation text
    int 地域,              // ?
    int リザルト有無,      // ?
    int 有利所属,          // ?
    int 有利属性1,        // Favorable attribute 1
    int 有利属性2,        // Favorable attribute 2
    string 選択画像,       // ?
    int クエストアウト可能 // ?
}

We’ll start by copying the row for the quest ★ハニーテスト and giving it a new ID and name,

    ...
    { 50, "★ハニーテスト", 10, "ハニーテスト", "デバッグ用です", "", "", "", 0, 0, 0, 0, 0, "", 0 },
    { 58, "MyQuest",       10, "My Quest",     "Tutorial quest", "", "", "", 0, 0, 0, 0, 0, "", 0 },
    ...

Always make sure that the first two columns (ID and name) are unique within the table.

Note that the ★ハニーテスト quest is a very simple debug quest with only a few events, a battle and a chest. We will start by copying the map for this quest and then make some edits to it.

Adding a map

Open the file ex/3_マップデータ.x and find the node named ★ハニーテスト (it should be right at the top). This is the map data for the quest that we copied in the previous step. Copy the entire node and rename it MyQuest,

    ...
    ★ハニーテスト = {
        サイズ = (list) { 25, 30 },
        データ = { ... }
    },
    MyQuest = {
        サイズ = (list) { 25, 30 },             // map size (x, y)
        データ = {
            0001 = {
                マップ位置 = (list) { 12, 15 }, // location (x, y) 
                種別 = "箱",                    // type (tile)
                番号 = 1,                       // tile number
            },
            0002 = {
                マップ位置 = (list) { 13, 15 }, // location (x,y)
                種別 = "道(─)",               // type (forward path)
            },
            0003 = {
                マップ位置 = (list) { 14, 15 },
                種別 = "道(─)",
            },
            0004 = {
                マップ位置 = (list) { 15, 15 },
                種別 = "箱",
                番号 = 20,
            },
            0005 = {
                マップ位置 = (list) { 16, 15 },
                種別 = "道(─)",
            },
            0006 = {
                マップ位置 = (list) { 17, 15 },
                種別 = "道(─)",
            },
            0007 = {
                マップ位置 = (list) { 18, 15 },
                種別 = "箱",
                番号 = 30,
            },
            0008 = {
                マップ位置 = (list) { 19, 15 },
                種別 = "道(─)",
            },
            0009 = {
                マップ位置 = (list) { 20, 15 },
                種別 = "道(─)",
            },
            0010 = {
                マップ位置 = (list) { 21, 15 },
                種別 = "箱",
                番号 = 40,
            },
            0011 = {
                マップ位置 = (list) { 22, 15 },
                種別 = "道(─)",
            },
            0012 = {
                マップ位置 = (list) { 23, 15 },
                種別 = "道(─)",
            },
            0013 = {
                マップ位置 = (list) { 24, 15 },
                種別 = "箱",
                番号 = 50,
            },
        },
    },
    ...

For now we’ll keep the map layout unchanged, but we’ll come back later to add a branch.

Adding tile data

Open the file ex/5_クエストデータ and find the node named ★ハニーテスト (it should be around line 582). This is the data for each tile on the map. If you look at the map data we copied in the previous step, you’ll notice that certain nodes have a key called 番号 which stores a number. Those numbers should correspond to the node names in this file.

Just like in the previous step, we will copy the entire node for ★ハニーテスト and rename it MyQuest,

    ...
    ★ハニーテスト = { ... }
    MyQuest = {
        背景 = "リーザス平原",            // background
        地名 = "リーザス",                // region name (displayed top left)
        音楽 = "フィールド/リーザス",    // music
        001 = {                        // data for map tile with 番号=1
            画像A = "街道1",            // tile image
            画像B = "イベント印",        // icon at tile (event icon)
            物語 = "000/テストさん",  // event function name
            選択分岐 = {                  // movement button data
                分岐前 = {                // move forward button
                    顔画像 = "立て看板",  // icon name
                    説明 = "出発します",  // button text
                },
            },
        },
        020 = {                        // data for map tile with 番号=20
            画像A = "街道1",            // tile image
            画像B = "中ボス魔軍印",      // icon at tile (mid-boss)
            戦闘 = "m22ハニー",           // battle name
            フラグ = "ウルトラレアON",  // flag to set
        },
        030 = {                        // data for map tile with 番号=30
            画像A = "街道1",            // tile image
            画像B = "レア宝箱印",        // icon at tile (rare chest)
            処理 = "宝箱/レア",          // processing (function name?)
        },
        040 = {                        // data for map tile with 番号=40
            画像A = "街道1",            // tile image
            画像B = "その頃印",          // icon at tile (other icon)
            物語 = "50/その頃",        // event function name
        },
        050 = {                        // data for map tile with 番号=50
            画像A = "街道1",            // tile image
            画像B = "イベント印",        // icon at tile (event icon)
            物語 = "50/エンド",        // event function name
            終了 = 1,                     // ends quest
        },
    },
    ...

Again, we’ll leave the data here unchanged and then come back later to add some new tiles.

Map decorations

There are various decorations that can be added to the map (buildings, trees, rocks, etc). They are specified in the file ex/39_障害物データ.x. Our map won’t have any, but we’ll copy the (empty) node for ★ハニーテスト and rename it as usual,

    ...
    ★ハニーテスト = {
        データ = {
        },
    },
    MyQuest = {
        データ = {
        },
    },
    ...

Adding the quest to the quest list

In order to add the quest to the quest list, we’ll have to write some code. Create a file called MyQuest.jaf and write the following code in it,

int added_extra_quests;

/*
 * Function which generates the list of preparation phase quests.
 */
override void T準備フェイズA(void)
{
    added_extra_quests = 0;
    super();
}

/*
 * Function to add a preparation phase quest to the list; called from within
 * T準備フェイズA.
 */
override void >準備フェイズ登録(string name)
{
    if (!added_extra_quests) {
        added_extra_quests = 1;
        >拠点フェイズ登録("MyQuest");
    }
    super(name);
}

Note that we have to use a bit of a hack here. The function T準備フェイズA is responsible for generating the list of preparation phase quests, and due to the way it’s implemented, quests can only be added to the list from within this function. In order to have our code run from within T準備フェイズA, we hook the function >準備フェイズ登録 and put our code there (using a global variable to prevent our code from running more than once per phase).

Building the mod

Now we can rebuild the .ex and .ain files to test our mod. First, rename the original files to src.ex and src.ain so that we don’t overwrite them. Then run the following commands to build the mod,

alice ex build -o Rance10EX.ex ex/main.x
alice ain edit -o Rance10.ain --jaf MyQuest.jaf src.ain

Now you can run the game and if everything goes well you should see a quest called “My Quest” on the first preparation phase (note: you have to start a new game in order for the quest to show up).

Creating an event

In order to create an ADV event, we have to write a function and then set the 物語 key in the クエストデータ table to the name of our function. Here’s an example of an event function, identical to the first event on the ★ハニーテスト quest,

void my_quest_event001(void)
{
    string aa = "500";                     // string variable
    ■壁紙("キャラ", -1, -1);               // set background CG
    ■背景("ランス城", -1, -1);             // set center CG
    ●台詞A("マジック/基本", "", "", ""); // set character CG

    '「ランス!!' R;                      // write text followed by a new line
    '「およそです」' A;                    // write text, then wait for input
    ●ト書き();                             // clear the text box

    '今日も、叱咤する声が';                // write text
    S(aa);                                 // write string variable
    'ランス城に響く。' A;                  // write text, then wait for input

    ●台詞A("ランス/基本", "", "", "");   // set character CG
    '「にっぽー」' A;                      // write text, then wait for input
    ■全立ち絵消し(-1);                     // clear character CGs
    ●ト書き();                             // clear message box

    '呟いて、マジックは保育園へと歩いていった。' A; // write text, then wait for input
}

Adjust it to your liking, then open the file ex/5_クエストデータ again and find the MyQuest node that we added earlier. In the 001 node (which corresponds to the start-of-quest tile), change the value of the 物語 key to "my_quest_event001",

    ...
    MyQuest = {
        背景 = "リーザス平原",
        地名 = "リーザス",
        音楽 = "フィールド/リーザス",
        001 = {
            画像A = "街道1",
            画像B = "イベント印",
            物語 = "my_quest_event001",
            選択分岐 = {
                分岐前 = {
                    顔画像 = "立て看板",
                    説明 = "出発します",
                },
            },
        },
        ...
    }
    ...

Adding a branch to the map

First, open the file ex/3_マップデータ.x.

Maps in Rance X are arranged in a 2D isometric grid, with the X axis extending towards the top right of the screen, and the Y axis extending towards the bottom right of the screen. Although the data is defined in terms of 2D coordinates, conceptually a map is a graph with vertices that you travel between and edges connecting them. Therefore I will use the terms “vertex” and “edge” to refer to cells on the grid which represent vertices and edges.

The ★ハニーテスト map consists of a straight line with a battle followed by a rare chest and a couple events. We will add a branch so that the player can choose to skip the battle.

The map currently looks like this,

1──20──30──40──50

We will change it to instead look like this,

┌──60──┐
1      30──40──50
└──20──┘

First, we need to lower vertex 20 and its surrounding edges. In the code below, the original data is commented out and the changed data is on the line below,

MyQuest = {
    ...
    0002 = {
        //マップ位置 = (list) { 13, 15 },
        マップ位置 = (list) { 13, 16 },
        種別 = "道(─)",
    },
    0003 = {
        //マップ位置 = (list) { 14, 15 },
        マップ位置 = (list) { 14, 16 },
        種別 = "道(─)",
    },
    0004 = {
        //マップ位置 = (list) { 15, 15 },
        マップ位置 = (list) { 15, 16 },
        種別 = "箱",
        番号 = 20,
    },
    0005 = {
        //マップ位置 = (list) { 16, 15 },
        マップ位置 = (list) { 16, 16 },
        種別 = "道(─)",
    },
    0006 = {
        //マップ位置 = (list) { 17, 15 },
        マップ位置 = (list) { 17, 16 },
        種別 = "道(─)",
    },
    ...
},

Then we add a couple new edge cells for the angled parts below vertices 1 and 30,

MyQuest = {
    ...
    "0014" = {
        マップ位置 = (list) { 12, 16 },
        種別 = "道(└)",
    },
    "0015" = {
        マップ位置 = (list) { 18, 16 },
        種別 = "道(┘)",
    },
},

Finally we’ll add the new vertex 60 and its surrounding edges,

MyQuest = {
    ...
    "0016" = {
        マップ位置 = (list) { 12, 14 },
        種別 = "道(┌)",
    },
    "0017" = {
        マップ位置 = (list) { 13, 14 },
        種別 = "道(─)",
    },
    "0018" = {
        マップ位置 = (list) { 14, 14 },
        種別 = "道(─)",
    },
    "0019" = {
        マップ位置 = (list) { 15, 14 },
        種別 = "箱",
        番号 = 60,
    },
    "0020" = {
        マップ位置 = (list) { 16, 14 },
        種別 = "道(─)",
    },
    "0021" = {
        マップ位置 = (list) { 17, 14 },
        種別 = "道(─)",
    },
    "0022" = {
        マップ位置 = (list) { 18, 14 },
        種別 = "道(┐)",
    },
},

With all this done, the map data should look like this,

MyQuest = {
    サイズ = (list) { 25, 30 },
    データ = {
        0001 = {
            マップ位置 = (list) { 12, 15 },
            種別 = "箱",
            番号 = 1,
        },
        0002 = {
            //マップ位置 = (list) { 13, 15 },
            マップ位置 = (list) { 13, 16 },
            種別 = "道(─)",
        },
        0003 = {
            //マップ位置 = (list) { 14, 15 },
            マップ位置 = (list) { 14, 16 },
            種別 = "道(─)",
        },
        0004 = {
            //マップ位置 = (list) { 15, 15 },
            マップ位置 = (list) { 15, 16 },
            種別 = "箱",
            番号 = 20,
        },
        0005 = {
            //マップ位置 = (list) { 16, 15 },
            マップ位置 = (list) { 16, 16 },
            種別 = "道(─)",
        },
        0006 = {
            //マップ位置 = (list) { 17, 15 },
            マップ位置 = (list) { 17, 16 },
            種別 = "道(─)",
        },
        0007 = {
            マップ位置 = (list) { 18, 15 },
            種別 = "箱",
            番号 = 30,
        },
        0008 = {
            マップ位置 = (list) { 19, 15 },
            種別 = "道(─)",
        },
        0009 = {
            マップ位置 = (list) { 20, 15 },
            種別 = "道(─)",
        },
        0010 = {
            マップ位置 = (list) { 21, 15 },
            種別 = "箱",
            番号 = 40,
        },
        0011 = {
            マップ位置 = (list) { 22, 15 },
            種別 = "道(─)",
        },
        0012 = {
            マップ位置 = (list) { 23, 15 },
            種別 = "道(─)",
        },
        0013 = {
            マップ位置 = (list) { 24, 15 },
            種別 = "箱",
            番号 = 50,
        },
        "0014" = {
            マップ位置 = (list) { 12, 16 },
            種別 = "道(└)",
        },
        "0015" = {
            マップ位置 = (list) { 18, 16 },
            種別 = "道(┘)",
        },
        "0016" = {
            マップ位置 = (list) { 12, 14 },
            種別 = "道(┌)",
        },
        "0017" = {
            マップ位置 = (list) { 13, 14 },
            種別 = "道(─)",
        },
        "0018" = {
            マップ位置 = (list) { 14, 14 },
            種別 = "道(─)",
        },
        "0019" = {
            マップ位置 = (list) { 15, 14 },
            種別 = "箱",
            番号 = 60,
        },
        "0020" = {
            マップ位置 = (list) { 16, 14 },
            種別 = "道(─)",
        },
        "0021" = {
            マップ位置 = (list) { 17, 14 },
            種別 = "道(─)",
        },
        "0022" = {
            マップ位置 = (list) { 18, 14 },
            種別 = "道(┐)",
        },
    },
},

Now all that’s left to do is define the CGs for the new vertex 60 and set up the branch at vertex 1. Open the file ex/5_クエストデータ.x and edit vertex 1 as follows,

MyQuest = {
    ...
    001 = {
        画像A = "街道1",
        画像B = "イベント印",
        物語 = "my_quest_event001",
        選択分岐 = {
            //分岐前 = {
            //    顔画像 = "立て看板",
            //    説明 = "出発します",
            //},
            分岐左 = {               // left (up) path
                顔画像 = "立て看板", // icon name
                説明 = "Run",        // button text
            },
            分岐右 = {              // right (down) path
                顔画像 = "ランス",  // icon name
                説明 = "Fight",     // button text
            },
        },
    },
    ...
},

Finally, create a new node for vertex 60 with the following contents,

MyQuest = {
    ...
    060 = {             // vertex 60
        画像A = "街道1", // tile CG
        画像B = "",       // empty tile
    },
},

Further reading

クエストデータ Reference
Rance X Modding Resources