What you will need
- WorldDialog Source*
- Visual Studio
- Flyff Source/Resource
- Text Editor
- A functioning brain
* If you don't have the WorldDialog Source, check the link and the guide below.
The Resource Part
To create an NPC, you first have to define it in the character.inc file. Let's so that now. I will just add a basic NPC with only the dialogue function.
Code:
MaFl_MyDiag
{
setting
{
AddMenu(MMI_DIALOG);
SetImage(IDS_CHARACTER_INC_000000);
m_szDialog="MaFl_MyDiag.txt";
}
SetName(IDS_CHARACTER_INC_000868);
}
Code:
IDS_CHARACTER_INC_000868 Custom NPC
You can now add the NPC somewhere in the World Editor to later test it in game.
The Source Part
Step 1: Defining the NPC Functions
Open NpcScript.h in Visual Studio. If you scroll down to about Line 120, you will start noticing a shitton of void functions with character-ids and then a number as the name.
These are actually the function declarations for what the NPC Dialogue will do.
Time to add your own then! You can add them almost anywhere in the CNpcScript class, but for good practice I'd advise you add them all the way at the bottom.
Code:
void mafl_mydiag_0(); void mafl_mydiag_1(); void mafl_mydiag_2(); void mafl_mydiag_3(); void mafl_mydiag_4(); void mafl_mydiag_5(); void mafl_mydiag_6(); void mafl_mydiag_7(); void mafl_mydiag_8(); void mafl_mydiag_9(); void mafl_mydiag_10();
Every NPC Script needs 11 functions, starting at 0, ending at 10 to properly work.
Now switch to NPCScript.cpp. Let's look at how the most basic NPC works.
Code:
void CNpcScript::dudk_kazen_0()
{
Speak( NpcId(), 53 );
SetScriptTimer( 15 );
}
void CNpcScript::dudk_kazen_1()
{
LaunchQuest();
}
void CNpcScript::dudk_kazen_2()
{
AddKey( 9 );
AddKey( 10 );
}
void CNpcScript::dudk_kazen_3()
{
Say ( 54 );
}
void CNpcScript::dudk_kazen_4()
{
Say ( 55 );
}
void CNpcScript::dudk_kazen_5()
{
}
void CNpcScript::dudk_kazen_6()
{
}
void CNpcScript::dudk_kazen_7()
{
}
void CNpcScript::dudk_kazen_8()
{
}
void CNpcScript::dudk_kazen_9()
{
Say( 56 );
}
void CNpcScript::dudk_kazen_10()
{
Say( 57 );
Exit();
}
Let me explain what they are for.
Speak
Speak is what the NPC will actually say as a text bubble over their head. The syntax is always the same, you supply the NpcId() function and the key.
SetScriptTimer
The interval the npc will perform this action.
Say
Say is the text that will be added when the user performs certain actions in the dialogue box.
AddKey
This is used to add functionality to an NPC.
LaunchQuest
Automatically adds quest functionality to the NPC.
Exit
Closes the dialoge box.
Now let me explain what the Key actually is. If you take a look at your resource folder, you can find the WorldDialog.txt file.
The key is the index in that file.
Please note: Indexation starts at 0, while line numbers always start at 1.
Therefore, Say(55) actually is line number 56, in this case:
Code:
Pha! A man ... Your race is not welcome here. You should get better.
Code:
Introduction Farewell
Let's get back to adding our own one. To make sure we actually know the keys of the dialogue texts, let's come up with some real quick.
Scroll all the way down in your WorldDialog.txt and add what you want to add. (You will need about 5 texts)
Here are mine:

As you can see my dialogues start at line number 1251, so at Key 1250.
Now, let's add the functions, you can pretty much just copy paste from the npc above, just change the keys.
If you were to recompile the WorldDialog now and properly merge everything into your client, you will notice that the Dialogue Box is still empty.
There is one more step you have to do do actually get your NPC working.
Open NpcScriptHelper.cpp
You will instantly see an enormous list of strings being applied to function pointers. This is basically what we need to do as well.
Scroll down until you reach the end of the list. (It's aboput 3200 lines down, crazy I know)
Now you can add your own function pointers.
Code:
{ "mafl_mydiag_0", &CNpcScript::mafl_mydiag_0 },
{ "mafl_mydiag_1", &CNpcScript::mafl_mydiag_1 },
{ "mafl_mydiag_2", &CNpcScript::mafl_mydiag_2 },
{ "mafl_mydiag_3", &CNpcScript::mafl_mydiag_3 },
{ "mafl_mydiag_4", &CNpcScript::mafl_mydiag_4 },
{ "mafl_mydiag_5", &CNpcScript::mafl_mydiag_5 },
{ "mafl_mydiag_6", &CNpcScript::mafl_mydiag_6 },
{ "mafl_mydiag_7", &CNpcScript::mafl_mydiag_7 },
{ "mafl_mydiag_8", &CNpcScript::mafl_mydiag_8 },
{ "mafl_mydiag_9", &CNpcScript::mafl_mydiag_9 },
{ "mafl_mydiag_10", &CNpcScript::mafl_mydiag_10 },
If you now go ingame, you will see this (you NPC will have the model you used in the world editor of course):

To recap:
Function 0
Setup the interval & text that will show as speech bubbles.
Function 1
Launch Quest functionality
Function 2
Add the "buttons" you want to add.
Function 3
To be completely honest I have no idea where this text will pop up.
Function 4
The first text you see when opening the dialogue box.
Function 6
From what I can tell so far, this is used for teleportation on quest-begin.
Code:
void CNpcScript::masa_wingyei_6()
{
if( GetQuestState(QUEST_VOCMAG_BFTRN) == QS_BEGIN )
{
Replace( WI_WORLD_MADRIGAL, 7161.0, 100.0, 3264.0 );
}
}
Although not shown in this example, this is where most NPCs have their JobChange functionality.
Code:
void CNpcScript::mafl_kidmen_8()
{
if( GetQuestState(QUEST_VOCASS_TRN3) == QS_END && GetPlayerJob() == 0 && GetPlayerLvl() == 15 )
{
ChangeJob(3);
InitStat();
}
else
{
Exit();
}
}
// or
void CNpcScript::masa_lopaze_8()
{
if( GetQuestState(QUEST_VOCMAG_TRN3) == QS_END && GetPlayerJob() == 0 && GetPlayerLvl() == 15 )
{
ChangeJob(4);
InitStat();
}
else
{
Exit();
}
}
Is what happens when you click Key 9 (Introduction)
Functon 10
Is what happens when you click Key 10 (Farewell)
Conclusion
I haven't bothered figuring out what exactly the NpcScript is capable of overall, this is just a basic guideline on how to add an npc with custom dialogues, which can be used for quests as well.
Also there are certain NPCs with over 30 functions, this probably is a remnant of the state system the Quests are using, but this is way too deep for me to bother.
I am sure there are some people out there who have looked into this way more than I did.
If so, feel free to either post an addition to the guide here or just send me a PM and I will add your contribution here.
A really interesting function for you to check out tho might be mad_redrobegirl_8() which handles the Master- and Hero-Jobchange
If you liked this small guide, don't forget to leave a Thanks.






