Server Guides Create a Quest

zLuke

Active Pirate
Registered
LV
0
 
Joined
Jan 29, 2026
Messages
36
Reaction score
8
Points
28

This guide was copied from the website
Please, Log in or Register to view URLs content!
, by the author Angelix


Simple Quest Part I
Collect an item, able to repeat after finishing.​
Adding a small format that will be explained below.

HTML:
    DefineMission(<QUEST_ID>, <QUEST_NAME>, <MISSION_ID>)

    MisBeginTalk(<MAIN_DIALOG>)

    MisBeginCondition(NoMission, <MISSION_ID>)
    MisBeginAction(AddMission, <MISSION_ID>)
    MisBeginAction(AddTrigger, <TRIGGERID>, TE_GETITEM, <ITEMINFO_ID>, <AMOUNT_NEEDED>)
    MisCancelAction(ClearMission, <MISSION_ID>)

    MisNeed(MIS_NEED_ITEM, <ITEMINFO_ID>, <AMOUNT_NEEDED>, <MISSION_FLAG>, <AMOUNT_NEEDED>)

    MisResultTalk(<COMPLETION_DIALOG>)

    MisHelpTalk(<HELP_DIALOG>)

    MisResultCondition(HasMission, <MISSION_ID>)
    MisResultCondition(HasItem, <ITEMINFO_ID>, <AMOUNT_NEEDED>)
    MisResultAction(TakeItem, <ITEMINFO_ID>, <AMOUNT_NEEDED>)
    MisResultAction(ClearMission, <MISSION_ID>)

    InitTrigger()
    TriggerCondition(1, IsItem, <ITEMINFO_ID>)
    TriggerAction(1, AddNextFlag, <MISSION_ID>, <MISSION_FLAG>, <AMOUNT_NEEDED>)
    RegCurTrigger(<TRIGGERID>)
Lets break it up into parts to explain, starting with this:
HTML:
    DefineMission(<QUEST_ID>, <QUEST_NAME>, <MISSION_ID>)
    MisBeginTalk(<MAIN_DIALOG>)
  • QUEST_ID: This is a number used to define the quest and the one that'll be going into the NPC, it must be a number that's not in used by any other quest.
  • QUEST_NAME: This will be the name of your quest, you can freely name your quest whatever your quest.
  • MISSION_ID: This number will be used throughout the quest to make conditions, actions and triggers. It must be a number that's not in used by any other quest.
    • There's an exception to this in some cases, like in story mission, where you talk to the first NPC then sends you to another NPC, both will have different quest IDs, but same mission IDs.
  • MAIN_DIALOG: You can place some text here like a brief story and tell players what to do.
Next step, conditions for the quest to show. Since this is a simple quest and a repeatable one, there's just one.
HTML:
    MisBeginCondition(NoMission, <MISSION_ID>)
Next step, adding the quest. Straight and simple, can't do much here.
HTML:
    MisBeginAction(AddMission, <MISSION_ID>)
Next step, adding the triggers. Here's where it gets a bit tricky with the trigger IDs.
HTML:
    MisBeginAction(AddTrigger, <TRIGGERID>, TE_GETITEM, <ITEMINFO_ID>, <AMOUNT_NEEDED>)
  • TRIGGERID: This is a number formed by two things: the mission ID and the trigger.
    • Lets say your mission ID is 2400 and this is your first trigger, then your trigger ID would be 24001, if it was your second trigger, then it would be 24002.
  • The "TE_GETITEM" is an identifier that refers to collect an item. There are several that are in the server files, but I don't know how to make use of them or make them work. The known ones are "TE_GETITEM" (to collect items) and "TE_KILL" (kill monsters).
  • ITEMINFO_ID: This the ID of the item you want to collect in the quest.
  • AMOUNT_NEED: The amount needed of the item to be collected.
Next step, MisNeed.
HTML:
    MisNeed(MIS_NEED_ITEM, <ITEMINFO_ID>, <AMOUNT_NEEDED>, <MISSION_FLAG>, <AMOUNT_NEEDED>)
  • MIS_NEED_ITEM: This goes along with "TE_GETITEM", if you wanted to kill a monster, then this needs to be changed as well.
  • ITEMINFO_ID: Already explained.
  • AMOUNT_NEEDED: Already explained.
  • MISSION_FLAG: This number goes by a multiple of 10. These should also be in the same order of the triggers. If it's the first flag, then it's 10, the second flag goes to 20 and so on.
  • AMOUNT_NEEDED: Already explained.
Next step, finishing dialog.
HTML:
    MisResultTalk(<COMPLETION_DIALOG>)
  • COMPLETION_DIALOG: This is the dialog that is shown to players when they successfully finish the quest.
Next step, help dialog.
HTML:
    MisHelpTalk(<HELP_DIALOG>)
  • HELP_DIALOG: This dialog is shown to players when they open the quest box corresponding to this mission, you can place hints or something else to help them remind where to find things.
Next step, conditions to finish quest.
HTML:
    MisResultCondition(HasMission, <MISSION_ID>)
    MisResultCondition(HasItem, <ITEMINFO_ID>, <AMOUNT_NEEDED>)
  • HasMission / MISSION_ID: This checks that the players still has the quest active.
  • ITEMINFO_ID: Already explained.
  • AMOUNT_NEEDED: Already explained.
Next step, what to do when player finished the quest.
HTML:
    MisResultAction(TakeItem, <ITEMINFO_ID>, <AMOUNT_NEEDED>)
    MisResultAction(ClearMission, <MISSION_ID>)
  • ITEMINFO_ID: Already explained.
  • AMOUNT_NEEDED: Already explained.
  • ClearMission: This will clear the mission from the players' quest log.
  • MISSION_ID: Already explained.
Last step, making the triggers.
HTML:
    InitTrigger()
    TriggerCondition(1, IsItem, <ITEMINFO_ID>)   
    TriggerAction(1, AddNextFlag, <MISSION_ID>, <MISSION_FLAG>, <AMOUNT_NEEDED>)
    RegCurTrigger(<TRIGGERID>)
  • IsItem: This will activate whenever a player collects an item and will check it with the ID given on the quest (the one defined as "ITEMINFO_ID"), if the IDs are the same, then it will add a check on the player's log and it will show a red notice on the player's screen saying "collected ITEM_NAME X/Y".
  • ITEMINFO_ID/MISSION_ID/MISSION_FLAG/AMOUNT_NEEDED/TRIGGERID: Already explained.

Simple Quest Part II
Making the players kill monster within the quest.​
Following the same format as the one above, we'll add an additional trigger to have players kill a certain amount of monsters.
HTML:
    MisBeginAction(AddTrigger, <TRIGGER_ID>, TE_KILL, <CHARACTERINFO_ID>, <AMOUNT_NEEDED>)
  • TRIGGER_ID: Is the same as above, mission ID plus the number of the trigger.
    • Example: If this is your first trigger and your mission ID is 2400, then this would be 24001, if it's your second trigger then it would be 24002.
  • TE_KILL: For killing monsters we use "TE_KILL" since "TE_GETITEM" belongs to the collection of items.
  • CHARACTER_INFO: This would be the ID of the monster according to your CharacterInfo.txt.
  • AMOUNT_NEEDED: Amount of monsters needed to kill.
We'll be adding a new "MisNeed".
HTML:
    MisNeed(MIS_NEED_KILL, <CHARACTERINFO_ID>, <AMOUNT_NEEDED>, <MISSION_FLAG>, <AMOUNT_NEEDED>)
  • MIS_NEED_KILL: This also changes, "MIS_NEED_KILL" corresponds to killing monsters while "MIS_NEED_ITEM" corresponds to collecting items.
  • CHARACTEROINFO_ID: Already explained.
  • AMOUNT_NEEDED: Already explained.
  • MISSION_FLAG: This number goes by a multiple of 10. These should also be in the same order of the triggers. If it's the first flag, then it's 10, the second flag goes to 20 and so on.
Adding a new condition to finish the quest.
HTML:
    MisResultCondition(HasFlag, <MISSION_ID>, <FLAG_PLUS_AMOUNT_MINUS_ONE>)
  • HasFlag: This changes to "HasFlag" (collecting items uses "HasItem") since the monsters killed will be stored in the quest log.
  • MISSION_ID: Already explained.
  • FLAG_PLUS_AMOUNT_MINUS_ONE: This is where it gets a bit tricky. You'll have to add the flag corresponding trigger, plus the amount of monsters needed to kill, minus one.
    • Example: If your flag for this trigger was 20 and you were asking to kill 5 monsters, then this number would be 24.
Making a new trigger.
HTML:
    InitTrigger()
    TriggerCondition(1, IsMonster, <CHARACTERINFO_ID>)   
    TriggerAction(1, AddNextFlag, <MISSION_ID>, <MISSION_FLAG>, <AMOUNT_NEEDED>)
    RegCurTrigger(<TRIGGER_ID>)
  • IsMonster: This will activate whenever a player kills a monster and will check it with the ID given on the quest (the one defined as "CHARACTERINFO_ID"), if the IDs are the same, then it will add a check on the player's log and it will show a red notice on the player's screen saying "kill MONSTER_NAME X/Y".
  • CHARACTERINFO_ID: Already explained.
  • MISSION_ID: Already explained.
  • MISSION_FLAG: Already explained.
  • AMOUNT_NEEDED: Already explained.
  • TRIGGER_ID: Already explained.

Simple Quest Part III
Now we will add the option to make the quest a non-repeatable one.​
Adding a new MisBeginCondition.
HTML:
    MisBeginCondition(NoRecord, <MISSION_ID>)
Adding a new MisResultAction.
HTML:
    MisResultAction(SetRecord, <MISSION_ID>)
Pretty easy and simple, self explanatory as well.

Simple Quest Part IV
Make the quest available only after completing another quest.​
Add a new MisBeginCondition as the one below.
HTML:
    MisBeginCondition(HasRecord, <MISSION_ID>)
Pretty easy and simple, self explanatory as well.

Simple Quest Part V
Make the quest available for certain levels.​
Lets start with the condition to begin the quest for certain levels, you would add this to the MisBeginCondition part of the quest.
HTML:
    MisBeginCondition(LvCheck, <CONDITION>, <PLAYER_LEVEL>)
  • CONDITION: You only have two choices here, either ">" (above) or "<" (below), you have to place the symbols along with the quotation marks.
  • PLAYER_LEVEL: You can set the level you want with the condition placed.
An example of this for players below a certain level would be:
HTML:
    MisBeginCondition(LvCheck, "<", 50)
  • Only players below level 50 can see this quest or accept it.
Another example for players above a certain level would be:
HTML:
    MisBeginCondition(LvCheck, ">", 45)
  • Only players above level 45 can see/accept this quest.
Another example can be a combination of both, for players within a certain range of levels:
HTML:
    MisBeginCondition(LvCheck, ">", 60)
    MisBeginCondition(LvCheck, "<", 75)
  • Only players above level 60, but below level 75, can see see/accept this quest.

Simple Quest Part VI
Make the quest available to certain classes.​
There are two types of conditions here, either make the quest available to a certain class or not available to a certain class.
Condition to make it available only to a certain class:
HTML:
    MisBeginCondition(PfEqual, <PLAYER_CLASS>)
Condition to make it available to everyone except a certain class:
HTML:
    MisResultCondition(NoPfEqual, <PLAYER_CLASS>)
  • PLAYER_CLASS: This refers to the number of a class, here are the currently used numbers for each class.
    • Newbie, 0.
    • Swordsman, 1.
    • Hunter, 2.
    • Explorer, 4.
    • Herbalist, 5.
    • Champion, 8.
    • Crusader, 9.
    • Sharpshooter, 12.
    • Cleric, 13.
    • Seal Master, 14.
    • Voyager, 16.
 
Custom Quest Part I
Making the players kill other players within the quest.​
In this part of the guide, I'll be showing you how to add a little trick to make quest that ask for killing players. It's a bit more complicated since you'll have to edit an already existing function, add a new function and a new line within CharacterInfo. You'll be following the same structure from Simple Quest Part II, I'll just show what to modify and add.

Lets start by adding a new line within CharacterInfo:
HTML:
<CHARACTERINFO_ID>    <CHARACTER_NAME>    Long Haired Guy    1    1    0    0    100    2000    255    464    640    816    0    0    0    0,0    0    0,0,0    1    1    100    182    -1    -1    0    0    0    1,2,3,4,7,8    1.051    1.369    2.599    40    1,5    0,0    399    398    0    0    0,0,0    1    1    0    0    25,28,29,30,31,34,35,38    100    0    0    0    0    0    0    0    1    1    1000    0    0    1    0    1    40    0    18    0    4    5    0    3    2    1    1    0    1    1    1442    0    1500    480    0    5    5    5    5    5    5    20    0    0    0    0    20    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    1.0,1.0,1.0
  • CHARACTERINFO_ID: This should be a new number not used.
  • CHARACTER_NAME: This should be the name you want to appear within the quest as it will appear as "Hunt <CHARACTER_NAME> X/Y", for this, just set it at "Players".
Then open up your functions.lua and add this somewhere inside:
HTML:
function CustomQuest(ATKER, DEFER)
    if HasMission(ATKER, <MISSION_ID>) == 1 then
        AddNextFlag(ATKER, <MISSION_ID>, <MISSION_FLAG>, <AMOUNT_NEEDED>)
        local Count = GetNumFlag(ATKER, <MISSION_ID>, <MISSION_FLAG>, <AMOUNT_NEEDED>)
        BickerNotice(ATKER, "Killed Players ["..Count.."/<AMOUNT_NEEDED>]!")
    end
end
Then within the same file, search for this function:
HTML:
after_player_kill_player
Inside that function, place this:
HTML:
CustomQuest(ATKER, DEFER)
Like I said, following the same structure as Simple Quest Part II, that will be everything you need to do in order to make the quest.

Custom Quest Part II
Making the players kill other players only within a certain map for the quest.​
Following the same structure from Custom Quest Part I.

Go to the function you have added:
HTML:
CustomQuest(ATKER, DEFER)
Replace this:
HTML:
function CustomQuest(ATKER, DEFER)
    if HasMission(ATKER, <MISSION_ID>) == 1 then
        AddNextFlag(ATKER, <MISSION_ID>, <MISSION_FLAG>, <AMOUNT_NEEDED>)
        local Count = GetNumFlag(ATKER, <MISSION_ID>, <MISSION_FLAG>, <AMOUNT_NEEDED>)
        BickerNotice(ATKER, "Killed Players ["..Count.."/<AMOUNT_NEEDED>]!")
    end
end
For this:
HTML:
function CustomQuest(ATKER, DEFER)
    if HasMission(ATKER, <MISSION_ID>) == 1 then
        if GetChaMapName(ATKER) == "<MAP_NAME>" then
            AddNextFlag(ATKER, <MISSION_ID>, <MISSION_FLAG>, <AMOUNT_NEEDED>)
            local Count = GetNumFlag(ATKER, <MISSION_ID>, <MISSION_FLAG>, <AMOUNT_NEEDED>)
            BickerNotice(ATKER, "Killed Players in <TRUE_MAP_NAME> ["..Count.."/<AMOUNT_NEEDED>]!")
        end
    end
end
  • MAP_NAME: This being the name of the map where you want kills to get registered only.
  • TRUE_MAP_NAME: This being the real name on the map you placed, example being "Forsaken City" for "abandonedcity".

Custom Quest Part III
Making the players kill other players that are only a certain class for the quest.​
Following the same structure from Custom Quest Part I.

Lets start by adding a new line within CharacterInfo:
HTML:
<CHARACTERINFO_ID>    <CLASS_NAME>    Long Haired Guy    1    1    0    0    100    2000    255    464    640    816    0    0    0    0,0    0    0,0,0    1    1    100    182    -1    -1    0    0    0    1,2,3,4,7,8    1.051    1.369    2.599    40    1,5    0,0    399    398    0    0    0,0,0    1    1    0    0    25,28,29,30,31,34,35,38    100    0    0    0    0    0    0    0    1    1    1000    0    0    1    0    1    40    0    18    0    4    5    0    3    2    1    1    0    1    1    1442    0    1500    480    0    5    5    5    5    5    5    20    0    0    0    0    20    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    1.0,1.0,1.0
  • CHARACTERINFO_ID: This should be a new number not used.
  • CLASS_NAME: The name of the class that will appear in the quest.
After that, we modify the following function:
HTML:
CustomQuest(ATKER, DEFER)
Change:
HTML:
function CustomQuest(ATKER, DEFER)
    if HasMission(ATKER, <MISSION_ID>) == 1 then
        AddNextFlag(ATKER, <MISSION_ID>, <MISSION_FLAG>, <AMOUNT_NEEDED>)
        local Count = GetNumFlag(ATKER, <MISSION_ID>, <MISSION_FLAG>, <AMOUNT_NEEDED>)
        BickerNotice(ATKER, "Killed Players ["..Count.."/<AMOUNT_NEEDED>]!")
    end
end
To:
HTML:
function CustomQuest(ATKER, DEFER)
    if HasMission(ATKER, <MISSION_ID>) == 1 then
        if GetChaAttr(DEFER, ATTR_JOB) == <CLASS_ID> then
            AddNextFlag(ATKER, <MISSION_ID>, <MISSION_FLAG>, <AMOUNT_NEEDED>)
            local Count = GetNumFlag(ATKER, <MISSION_ID>, <MISSION_FLAG>, <AMOUNT_NEEDED>)
            BickerNotice(ATKER, "Killed <CLASS_NAME> Players ["..Count.."/<AMOUNT_NEEDED>]!")
        end
    end
end
  • CLASS_ID: This is the number belonging to the class you chose to create the CharacterInfo ID.
    • If you chose "Crusader", then this would be 9, and so on.
  • CLASS_NAME: The true name of the class you chose to put in this quest.

Custom Quest Part IV
Making the players kill other players that are only a certain type of character for the quest.​
Following the same structure from Custom Quest Part I.

Lets start by adding a new line within CharacterInfo:
HTML:
<CHARACTERINFO_ID>    <CHARACTER_NAME>    Long Haired Guy    1    1    0    0    100    2000    255    464    640    816    0    0    0    0,0    0    0,0,0    1    1    100    182    -1    -1    0    0    0    1,2,3,4,7,8    1.051    1.369    2.599    40    1,5    0,0    399    398    0    0    0,0,0    1    1    0    0    25,28,29,30,31,34,35,38    100    0    0    0    0    0    0    0    1    1    1000    0    0    1    0    1    40    0    18    0    4    5    0    3    2    1    1    0    1    1    1442    0    1500    480    0    5    5    5    5    5    5    20    0    0    0    0    20    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    0    1.0,1.0,1.0
  • CHARACTERINFO_ID: This should be a new number not used.
  • CHARACTER_NAME: The name of the type of character that will appear in the quest.
After that, we modify the following function:
HTML:
CustomQuest(ATKER, DEFER)
Change:
HTML:
function CustomQuest(ATKER, DEFER)
    if HasMission(ATKER, <MISSION_ID>) == 1 then
        AddNextFlag(ATKER, <MISSION_ID>, <MISSION_FLAG>, <AMOUNT_NEEDED>)
        local Count = GetNumFlag(ATKER, <MISSION_ID>, <MISSION_FLAG>, <AMOUNT_NEEDED>)
        BickerNotice(ATKER, "Killed Players ["..Count.."/<AMOUNT_NEEDED>]!")
    end
end
To:
HTML:
function CustomQuest(ATKER, DEFER)
    if HasMission(ATKER, <MISSION_ID>) == 1 then
        if GetChaTypeID(DEFER) == <CHARACTER_ID> then
            AddNextFlag(ATKER, <MISSION_ID>, <MISSION_FLAG>, <AMOUNT_NEEDED>)
            local Count = GetNumFlag(ATKER, <MISSION_ID>, <MISSION_FLAG>, <AMOUNT_NEEDED>)
            BickerNotice(ATKER, "Killed <CHARACTER_NAME> Players ["..Count.."/<AMOUNT_NEEDED>]!")
        end
    end
end
  • CHARACTER_ID: This is the number belonging to the character type you chose to create the CharacterInfo ID.
    • If you chose "Lance", then this would be 1.
    • If you chose "Carsise", then this would be 2.
    • If you chose "Phyllis", then this would be 3.
    • If you chose "Ami", then this would be 4.

Custom Quest Part V
Making the players kill other players that are inside a certain map and are a certain type of character for the quest.​
This is a mixed type from Custom Quest Part II and Custom Quest Part IV.

You only need to modify the following function:
HTML:
CustomQuest(ATKER, DEFER)
Change:
HTML:
function CustomQuest(ATKER, DEFER)
    if HasMission(ATKER, <MISSION_ID>) == 1 then
        if GetChaTypeID(DEFER) == <CHARACTER_ID> then
            AddNextFlag(ATKER, <MISSION_ID>, <MISSION_FLAG>, <AMOUNT_NEEDED>)
            local Count = GetNumFlag(ATKER, <MISSION_ID>, <MISSION_FLAG>, <AMOUNT_NEEDED>)
            BickerNotice(ATKER, "Killed Players ["..Count.."/<AMOUNT_NEEDED>]!")
        end
    end
end
To:
HTML:
function CustomQuest(ATKER, DEFER)
    if HasMission(ATKER, <MISSION_ID>) == 1 then
        if GetChaMapName(DEFER) == "<MAP_NAME>" then
            if GetChaTypeID(DEFER) == <CHARACTER_ID> then
                AddNextFlag(ATKER, <MISSION_ID>, <MISSION_FLAG>, <AMOUNT_NEEDED>)
                local Count = GetNumFlag(ATKER, <MISSION_ID>, <MISSION_FLAG>, <AMOUNT_NEEDED>)
                BickerNotice(ATKER, "Killed <CHARACTER_NAME> Players in <TRUE_MAP_NAME> ["..Count.."/<AMOUNT_NEEDED>]!")
            end
        end
    end
end
  • The variables are already explained in other parts of the guide.

Custom Quest Part VI
Making the players kill other players that are inside a certain map and are a certain type of class for the quest.​
This is a mixed type from Custom Quest Part II and Custom Quest Part III.

You only need to modify the following function:
HTML:
CustomQuest(ATKER, DEFER)
Change:
HTML:
function CustomQuest(ATKER, DEFER)
    if HasMission(ATKER, <MISSION_ID>) == 1 then
        AddNextFlag(ATKER, <MISSION_ID>, <MISSION_FLAG>, <AMOUNT_NEEDED>)
        local Count = GetNumFlag(ATKER, <MISSION_ID>, <MISSION_FLAG>, <AMOUNT_NEEDED>)
        BickerNotice(ATKER, "Killed Players ["..Count.."/<AMOUNT_NEEDED>]!")
    end
end
To:
HTML:
function CustomQuest(ATKER, DEFER)
    if HasMission(ATKER, <MISSION_ID>) == 1 then
        if GetChaMapName(DEFER) == "<MAP_NAME>" then
            if GetChaAttr(DEFER, ATTR_JOB) == <CLASS_ID> then
                AddNextFlag(ATKER, <MISSION_ID>, <MISSION_FLAG>, <AMOUNT_NEEDED>)
                local Count = GetNumFlag(ATKER, <MISSION_ID>, <MISSION_FLAG>, <AMOUNT_NEEDED>)
                BickerNotice(ATKER, "Killed <CLASS_NAME> Players <TRUE_MAP_NAME> ["..Count.."/<AMOUNT_NEEDED>]!")
            end
        end
    end
end
  • The variables are already explained in other parts of the guide.

Custom Quest Part VII
Making the players kill other players that are only a certain type of character and class for the quest.​
This is a mixed type from Custom Quest Part III and Custom Quest Part IV.

You only need to modify the following function:
HTML:
CustomQuest(ATKER, DEFER)
Change:
HTML:
function CustomQuest(ATKER, DEFER)
    if HasMission(ATKER, <MISSION_ID>) == 1 then
        AddNextFlag(ATKER, <MISSION_ID>, <MISSION_FLAG>, <AMOUNT_NEEDED>)
        local Count = GetNumFlag(ATKER, <MISSION_ID>, <MISSION_FLAG>, <AMOUNT_NEEDED>)
        BickerNotice(ATKER, "Killed Players ["..Count.."/<AMOUNT_NEEDED>]!")
    end
end
To:
HTML:
function CustomQuest(ATKER, DEFER)
    if HasMission(ATKER, <MISSION_ID>) == 1 then
        if GetChaTypeID(DEFER) == <CHARACTER_ID> then
            if GetChaAttr(DEFER, ATTR_JOB) == <CLASS_ID> then
                AddNextFlag(ATKER, <MISSION_ID>, <MISSION_FLAG>, <AMOUNT_NEEDED>)
                local Count = GetNumFlag(ATKER, <MISSION_ID>, <MISSION_FLAG>, <AMOUNT_NEEDED>)
                BickerNotice(ATKER, "Killed <CHARACTER_NAME> <CLASS_NAME> Players ["..Count.."/<AMOUNT_NEEDED>]!")
            end
        end
    end
end
  • The variables are already explained in other parts of the guide.

Custom Quest Part VIII
Making the players kill other players that are inside a certain map, are a certain class and a certain type of character.​
This is a mixed type from Custom Quest Part II, Custom Quest Part III and Custom Quest Part IV.

You only need to modify the following function:
HTML:
CustomQuest(ATKER, DEFER)
Change:
HTML:
function CustomQuest(ATKER, DEFER)
    if HasMission(ATKER, <MISSION_ID>) == 1 then
        AddNextFlag(ATKER, <MISSION_ID>, <MISSION_FLAG>, <AMOUNT_NEEDED>)
        local Count = GetNumFlag(ATKER, <MISSION_ID>, <MISSION_FLAG>, <AMOUNT_NEEDED>)
        BickerNotice(ATKER, "Killed Players ["..Count.."/<AMOUNT_NEEDED>]!")
    end
end
To:
HTML:
function CustomQuest(ATKER, DEFER)
    if HasMission(ATKER, <MISSION_ID>) == 1 then
        if GetChaMapName(DEFER) == "<MAP_NAME>" then
            if GetChaTypeID(DEFER) == <CHARACTER_ID> then
                if GetChaAttr(DEFER, ATTR_JOB) == <CLASS_ID> then
                    AddNextFlag(ATKER, <MISSION_ID>, <MISSION_FLAG>, <AMOUNT_NEEDED>)
                    local Count = GetNumFlag(ATKER, <MISSION_ID>, <MISSION_FLAG>, <AMOUNT_NEEDED>)
                    BickerNotice(ATKER, "Killed <CHARACTER_NAME> <CLASS_NAME> Players in <TRUE_MAP_NAME> ["..Count.."/<AMOUNT_NEEDED>]!")
                end
            end
        end
    end
end
  • The variables are already explained in other parts of the guide.

Custom Quest Part IX
Making the quest only able to repeat once per day or per week.​
This is somewhat the same as Simple Quest Part III.

You need to add the following functions to MissionSdk.lua:
HTML:
function getYearBeginDayOfWeek(tm)
    local yearBegin = os.time{year=os.date("*t",tm).year,month=1,day=1}
    local yearBeginDayOfWeek = tonumber(os.date("%w",yearBegin))
    if (yearBeginDayOfWeek == 0) then
        yearBeginDayOfWeek = 7
    end
    return yearBeginDayOfWeek
end
function getDayAdd(tm)
    local yearBeginDayOfWeek = getYearBeginDayOfWeek(tm)
    local dayAdd = 0
    if (yearBeginDayOfWeek < 5) then
        dayAdd = (yearBeginDayOfWeek - 2)
    else 
        dayAdd = (yearBeginDayOfWeek - 9)
    end  
    return dayAdd
end
function getWeekNumberOfYear()
    local tm = os.time{year=tonumber(os.date("%Y")),month=tonumber(os.date("%m")),day=tonumber(os.date("%d"))}
    local dayOfYear = os.date("%j",tm)
    local dayAdd = getDayAdd(tm)
    local dayOfYearCorrected = dayOfYear + dayAdd
    if (dayOfYearCorrected < 0) then
        dayAdd = getDayAdd(os.time{year=os.date("*t",tm).year-1,month=1,day=1})
        dayOfYear = dayOfYear + os.date("%j", (os.time{year=os.date("*t",tm).year-1,month=12,day=31}))
        dayOfYearCorrected = dayOfYear + dayAdd
    end  
    local weekNum = math.floor((dayOfYearCorrected) / 7) + 1
    if ((dayOfYearCorrected > 0) and weekNum == 53) then
        if (getYearBeginDayOfWeek(os.time{year=os.date("*t",tm).year+1,month=1,day=1}) < 5 ) then
            weekNum = 1
        end  
    end  
    return weekNum
end
function QuestFunc(Player, Mission, Type, Func)
    local Name = GetChaDefaultName(Player)
    local Day = (tonumber(os.date("%Y")) * 10000) + (tonumber(os.date("%m")) * 100) + (tonumber(os.date("%d")))
    local Week = (tonumber(os.date("%Y")) * 100) + getWeekNumberOfYear()
    if QuestLog == nil then
        QuestLog = {}
    end
    if QuestLog[Name] == nil then
        QuestLog[Name] = {}
    end
    if QuestLog[Name][Mission] == nil then
        QuestLog[Name][Mission] = {}
    end
    if Type == "Daily" then
        if QuestLog[Name][Mission][Day] == nil then
            QuestLog[Name][Mission][Day] = false
        end
        if Func == "Check" then
            if QuestLog[Name][Mission][Day] == false then
                return LUA_TRUE
            elseif QuestLog[Name][Mission][Day] == true then
                return LUA_FALSE
            end
        elseif Func == "Completed" then
            QuestLog[Name][Mission][Day] = true
            return LUA_TRUE
        end
    elseif Type == "Weekly" then
        if QuestLog[Name][Mission][Week] == nil then
            QuestLog[Name][Mission][Week] = false
        end
        if Func == "Check" then
            if QuestLog[Name][Mission][Week] == false then
                return LUA_TRUE
            elseif QuestLog[Name][Mission][Week] == true then
                return LUA_FALSE
            end
        elseif Func == "Completed" then
            QuestLog[Name][Mission][Week] = true
            return LUA_TRUE
        end
    end
end
Within the same file, look for:
HTML:
            elseif conditions[i].func == NoRecord then
                    ..
                end
Then right above (or below) it, add this:
HTML:
            elseif conditions[i].func == QuestFunc then
                local ret = QuestFunc(character, conditions[i].p1, conditions[i].p2, conditions[i].p3)
                if ret ~= LUA_TRUE then
                    return LUA_FALSE
                end
Then, within the same file look for this:
HTML:
        elseif actions[i].func == SetRecord then
                ...
            end
Then right above (or below) it, add this:
HTML:
        elseif actions[i].func == QuestFunc then
            local ret = QuestFunc(character, actions[i].p1, actions[i].p2, actions[i].p3)
            if ret ~= LUA_TRUE then
                return LUA_FALSE
            end
Then, as mentioned above, doing the same thing as Simple Quest Part III, but with a little change:

Add this MisBeginCondition:
HTML:
MisBeginCondition(QuestFunc, <MISSION_ID>, <MISSION_TYPE>, "Check")
Then add this MisResultAction:
HTML:
MisResultAction(QuestFunc, <MISSION_ID>, <MISSION_TYPE>, "Completed")
  • MISSION_ID: This being the ID of your mission.
  • MISSION_TYPE: This can only be two choices (they have to be typed as followed, even with quotation marks):
    • "Daily": Quest only repeatable once a day.
    • "Weekly": Quest only repeatable once a week.
DISCLAIMER: These "daily" or "weekly" quest will not persists through server restarts, if you want them to persists, modify function in order to work with text logs.
 
Extra Quest Functions Part I
Adding rewards to quests.​
Taking a look at the format from "Simple Quest Part I", you can add some functions to give players items, gold or do other actions.

After this line:
HTML:
MisResultAction(ClearMission, <MISSION_ID>)
You can either go two ways about adding items or gold as rewards. This method will not show anything, just give the rewards to the player when completing the quest. You can add this lines below the line mentioned above.
HTML:
MisResultAction(AddExp, <AMOUNT_EXP_START>, <AMOUNT_EXP_END>)
MisResultAction(AddMoney, <AMOUNT_GOLD_START>, <AMOUNT_GOLD_END>)
  • It will give a random amount of experience between "<AMOUNT_EXP_START>" and "<AMOUNT_EXP_END>", it will give a set amount of experience if both numbers are the same.
  • It will give a random amount of gold between "<AMOUNT_GOLD_START>" and "<AMOUNT_GOLD_END>", it will give a set amount of experience if both numbers are the same.
You can also go with a more visual way of adding rewards by adding these below "MisResultAction(ClearMission, <MISSION_ID>)":
HTML:
MisResultBagNeed(<SPACES_NEEDED>)
MisPrize(MIS_PRIZE_ITEM, <ITEM_ID>, <ITEM_QUANTITY>, <ITEM_QUALITY>)
MisPrize(MIS_PRIZE_MONEY, <GOLD_AMOUNT>, 1)
MisPrizeSelAll()
The needed things are pretty much self explanatory and by using this method, it will show at all times the rewards that will be obtained in the quest log.

Extra Quest Functions Part II
Adding the quest to an NPC.​
For the player to be able to obtain the quest, they need to talk to an NPC, it's very easy to add.
You take this first line you created:

HTML:
DefineMission(<QUEST_ID>, <QUEST_NAME>, <MISSION_ID>)
With that, you add this at the end of the NPC you want players to obtain the quest.
HTML:
AddNpcMission(<QUEST_ID>)

Extra Quest Functions Part III
Adding the quest to the client so it shows the proper name on quest log.​
With this line:
HTML:
DefineMission(<QUEST_ID>, <QUEST_NAME>, <MISSION_ID>)
You open up your client files and open this specific file: Client\scripts\lua\mission\missioninfo.lua and then add this in there:
HTML:
AddMisData(<MISSION_ID>, <QUEST_NAME>, <QUEST_TYPE>)
  • <MISSION_ID>: Same as the first line of the quest created.
  • <QUEST_NAME>: Same as the quest name in first line.
  • <QUEST_TYPE>: You can put "1" being a normal quest or "2" being a story quest.