Angelix 374 Report post Posted November 17, 2016 (edited) I'll be making a guide on how to create your own custom quests. I'll be going through the simple ones and maybe add a few conditions there. Enjoy. Simple Quest Part I Collect an item, able to repeat after finishing. Spoiler Adding a small format that will be explained below. 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: 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. MisBeginCondition(NoMission, <MISSION_ID>) Next step, adding the quest. Straight and simple, can't do much here. MisBeginAction(AddMission, <MISSION_ID>) Next step, adding the triggers. Here's where it gets a bit tricky with the trigger IDs. MisBeginAction(AddTrigger, <TRIGGERID>, TE_GETITEM, <ITEMINFO_ID>, <AMOUNT_NEEDED>) TRIGGER_ID: 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. 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. MisResultTalk(<COMPLETION_DIALOG>) COMPLETION_DIALOG: This is the dialog that is shown to players when they successfully finish the quest. Next step, help dialog. 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. 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. 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. 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. Spoiler Following the same format as the one above, we'll add an additional trigger to have players kill a certain amount of monsters. 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". 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. 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. 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. Spoiler Adding a new MisBeginCondition. MisBeginCondition(NoRecord, <MISSION_ID>) Adding a new MisResultAction. 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. Spoiler Add a new MisBeginCondition as the one below. MisBeginCondition(HasRecord, <MISSION_ID>) Pretty easy and simple, self explanatory as well. Simple Quest Part V Make the quest available for certain levels. Spoiler Lets start with the condition to begin the quest for certain levels, you would add this to the MisBeginCondition part of the quest. 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: 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: 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: 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. Spoiler 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: MisBeginCondition(PfEqual, <PLAYER_CLASS>) Condition to make it available to everyone except a certain class: 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. Sharshooter, 12. Cleric, 13. Seal Master, 14. Voyager, 16. This is everything needed to make a simple quest. Edited February 6, 2017 by Angelix 17 1 Quote Share this post Link to post Share on other sites
Angelix 374 Report post Posted November 17, 2016 Custom Quest Part I Making the players kill other players within the quest. Spoiler 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: <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: 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: after_player_kill_player Inside that function, place this: 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. Spoiler Following the same structure from Custom Quest Part I. Go to the function you have added: CustomQuest(ATKER, DEFER) Replace this: 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: 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. Spoiler Following the same structure from Custom Quest Part I. Lets start by adding a new line within CharacterInfo: <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: CustomQuest(ATKER, DEFER) Change: 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: 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. Spoiler Following the same structure from Custom Quest Part I. Lets start by adding a new line within CharacterInfo: <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: CustomQuest(ATKER, DEFER) Change: 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: 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. Spoiler This is a mixed type from Custom Quest Part II and Custom Quest Part IV. You only need to modify the following function: CustomQuest(ATKER, DEFER) Change: 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: 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. Spoiler This is a mixed type from Custom Quest Part II and Custom Quest Part III. You only need to modify the following function: CustomQuest(ATKER, DEFER) Change: 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: 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. Spoiler This is a mixed type from Custom Quest Part III and Custom Quest Part IV. You only need to modify the following function: CustomQuest(ATKER, DEFER) Change: 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: 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. Spoiler 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: CustomQuest(ATKER, DEFER) Change: 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: 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. Spoiler This is somewhat the same as Simple Quest Part III. You need to add the following functions to MissionSdk.lua: 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: elseif conditions[i].func == NoRecord then .. end Then right above (or below) it, add this: 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: elseif actions[i].func == SetRecord then ... end Then right above (or below) it, add this: 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: MisBeginCondition(QuestFunc, <MISSION_ID>, <MISSION_TYPE>, "Check") Then add this MisResultAction: 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. 4 1 Quote Share this post Link to post Share on other sites
Angelix 374 Report post Posted November 17, 2016 (edited) Extra Quest Functions Part I Adding rewards to quests. Quote 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: 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. 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>)": 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. Quote 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: 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. AddNpcMission(<QUEST_ID>) Extra Quest Functions Part III Adding the quest to the client so it shows the proper name on quest log. Quote With this line: 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: 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. Edited October 22, 2018 by Angelix Added guide to add quest to NPC. 1 Quote Share this post Link to post Share on other sites
Angelix 374 Report post Posted December 6, 2016 (edited) Updated, enjoy. Added a part to show how to chain quests, by making a condition to have another quest already completed in order to start the new quest. Maybe in the next days I'll put up the part on how to make a quest that requires you to talk to other NPCs, just like the quest originally used in ToP that asks you to talk to other NPCs to become a voyager. Edited December 6, 2016 by Angelix 2 1 Quote Share this post Link to post Share on other sites
Jap 189 Report post Posted December 6, 2016 nice job dude. Quote Share this post Link to post Share on other sites
Angelix 374 Report post Posted December 6, 2016 12 hours ago, Jap said: nice job dude. Thanks! Quote Share this post Link to post Share on other sites
Maximilian 25 Report post Posted December 7, 2016 (edited) @Angelix I would suggest explanaining how to put 'randomized' items needed/mobs to kill/ rewards (from a list), such as in Class Quests (like a Swordsman's Life / Hunter's Life etc). It is a mechanic that if i will ever get back to making novel servers i will use (and i know how, it should be public that's all). Edit : forgot to tag Edited December 7, 2016 by Maximilian Quote Share this post Link to post Share on other sites
Angelix 374 Report post Posted December 7, 2016 7 minutes ago, Maximilian said: @Angelix I would suggest explanaining how to put 'randomized' items needed/mobs to kill/ rewards (from a list), such as in Class Quests (like a Swordsman's Life / Hunter's Life etc). It is a mechanic that if i will ever get back to making novel servers i will use (and i know how, it should be public that's all). Edit : forgot to tag I don't know yet how exactly they work, give me some minutes since I'm currently updating this guide in another tab, hahah. Adding a new type of quest. Quote Share this post Link to post Share on other sites
Maximilian 25 Report post Posted December 7, 2016 @Angelix Oh the class quests i listed are fairly self explanatory, it's not hard to grasp at all. I am on mobile so pardon me for my likely inaccuracy but as far as i remember, it's a series of strings with the level requiremet, the kind of mob and the likelyhood you have to get it compared to other (and how many). There is one different sub-function for each kind of 'subject' , being defined as either mobs/items/rewards. Quote Share this post Link to post Share on other sites
Angelix 374 Report post Posted December 7, 2016 Guide has been updated with a custom feature, I will later amplify more requirements on that function, enjoy. 1 minute ago, Maximilian said: @Angelix Oh the class quests i listed are fairly self explanatory, it's not hard to grasp at all. I am on mobile so pardon me for my likely inaccuracy but as far as i remember, it's a series of strings with the level requiremet, the kind of mob and the likelyhood you have to get it compared to other (and how many). There is one different sub-function for each kind of 'subject' , being defined as either mobs/items/rewards. I'll take a look when I can and then write here how to make them as part of the guide. 1 Quote Share this post Link to post Share on other sites
SoundX 14 Report post Posted December 7, 2016 This is great guide very useful! 7 hours ago, Angelix said: I'll take a look when I can and then write here how to make them as part of the guide. This maybe helpful, I had asked about random quests in the past I think in serverdv forum and this is how I think it work: (though I didn't finally do it, so some things I still don't know what is) Random mob to kill: AddRandKillInfo( level , monsterid, randvalue, randscope, exp , money ) AddRandKillInfo( 10 , 206 , 3 , 2 , 4028 , 4000 ) 10 = Char level 206= id of mob to hunt (mini bee in this one) 3 = minimum number of mobs to hunt 2 = variation: minimun number + 2, quest can ask kill 3, 4, or 5 (3+2) mobs 4028: Quest gives 201g money reward at round 1 (roughly 4028/20) and each round increases by 40 (2 first digits) 4000: Quest give 200exp first round (4000/20) and increase 40 each round Random item to collect: AddRandGetItem( level, itemid, randvalue, randscope, exp, money ) AddRandGetItem( 10 , 4485 , 3 , 2 , 4028 , 4000 ) Same as above: 10 = Char level 4485= id of item to collect (Bee Wing) 3 = min number of items 2 = variation 4028 and 4000: money and exp as above Random give item to other NPC: AddRandSendInfo( level, npcid, exp, money ) AddRandSendInfo( 80 , 41 , 727500 , 86569 ) AddRandSendItem( level, item ) AddRandSendItem( 80 , 1850 ) 80 = level 41 = npc ID 727500 and 86569 money and exp 1850 is parcel Price (randomised) SetRandPrizeItem( level ) SetRandPrizeItem( 10 ) AddRandPrizeItem( level, item1, itemdata1, item2, itemdata2, item3, itemdata3, item4, itemdata4 ) AddRandPrizeItem( 10 , 290 , 810 ) level 10, item reward 290 (husk armor) and itemdata 810 I am not sure what means Cycling quests (quest complete every 10 rounds) SetRandPrizeOdds( loopnum, odds, completenum ) SetRandPrizeOdds( 1, 100, 10 ) completenum (10) is the number of quests to complete a cycle. I don't know how the other two are cacluleted 4 Quote Share this post Link to post Share on other sites
MonkeyCode 453 Report post Posted December 7, 2016 ladies and gentlemen, this is how a guide should be. Neat, Clean, and Organized. Nice job @Angelix 1 Quote Share this post Link to post Share on other sites
Angelix 374 Report post Posted December 8, 2016 17 hours ago, KONG said: ladies and gentlemen, this is how a guide should be. Neat, Clean, and Organized. Nice job @Angelix Thanks for the sticky as well! I've been busy with some final things at school this week, so probably on the weekend I'll update it a bit including the randomizer example/request given by @Maximilian and @SoundX. I'll also try to add to make daily and weekly quests, along with more derivations from the "kill players" conditions, such as map, class and character type specific conditions. 2 Quote Share this post Link to post Share on other sites
Angelix 374 Report post Posted December 11, 2016 The guide has been updated with more custom features, enjoy! The following has been added: Ask players to kill within a certain map. Ask players to kill a certain class (ex: crusader, champion, etc.). Ask players to kill a certain type of character (ex: lance, carsise, phyllis or ami). Ask players to kill a certain class within a map (ex: abandonedcity, darkswamp, etc.). Ask players to kill a type of character within a map (ex: a crusader in abandonedcity). Ask players to kill a type of class and character type (ex: a lance crusader). Ask players to kill a type of class and character within a map (ex: a lance crusader within abandonedcity). Make daily or weekly quest. Please notice that this has been untested and may not work, although I think daily quest should work, not sure about weekly. Note: Even after been told where to look and explained a bit, I haven't got around messing with the randomized quest, that is what I'm going to do next, I think. 1 Quote Share this post Link to post Share on other sites
Angelix 374 Report post Posted December 17, 2016 (edited) The guide has been updated, enjoy! Updates: Fixed some typos in the guide. Add a triggered BIckerNotice to the custom quest when killing players, you may adjust that now to your needs. Issues: The BickerNotice persists even after completing the amount of kills needed. Small Update Edit: Apply this and it should fix the above mentioned issue of the spamming of BickerNotice, although it was tested a bit, an issue may occur when having two of the same flags; example being your first flag being 10 and the amount needed being 11 resulting in 20, while your second flag being 20 with the amount needed being 1, resulting in 20 as well. Well, that's also an issue with normal monster killing quests though, not my issue. Other than that, I don't think any more issues will arise, if they do, please let me know by making a comment and I'll try to see if the fix is within my knowledge. I was editing the whole thread on custom quests with the new modifications and had a little error when trying to save, I lost all the progress and I'm too lazy to go again and edit it, so just use the following piece of code to fix the issue. Please use this as the base and modify to your needs. function CustomQuest(ATKER, DEFER) if HasMission(ATKER, <MISSION_ID>) == 1 then if IsFlag(ATKER, <MISSION_ID>, <FLAG_PLUS_AMOUNT_MINUS_ONE>) == 0 then AddNextFlag(ATKER, <MISSION_ID>, <MISSION_FLAG>, <AMOUNT_NEEDED>) end end end Small Note (to myself): Save the thread after every single edit made, never know when there's going to be a quick blackout and won't be able to save the thread later. Enjoy! Edited December 17, 2016 by Angelix 1 Quote Share this post Link to post Share on other sites
TheSamurai 3 Report post Posted December 17, 2016 (edited) Thanks @Angelix BickerNotice is working properly now. Edited December 17, 2016 by TheSamurai Quote Share this post Link to post Share on other sites
Angelix 374 Report post Posted December 17, 2016 13 hours ago, TheSamurai said: Thanks @Angelix BickerNotice is working properly now. Glad to hear that, if any issue shows up regarding that, please let me know so I can see if there's fix for it. 1 Quote Share this post Link to post Share on other sites
blazi10 37 Report post Posted February 4, 2017 Got this error with Daily Quest http://screenshot.sh/m1QsTif8T73Kv can you help me?' its my function NpcState: function NpcState( character, npcid, id ) PRINT( "NpcState:character, npcid, NpcMissionList", character, npcid, id ) if NpcInfoList[id] == nil or NpcInfoList[id].missionlist == nil then PRINT( "unable to obtain NPC script notice!ID = ", id ) LG( "npc_error", "unable to obtain NPC script notice!ID = ", id ) return LUA_FALSE end return MissionState( character, npcid, NpcInfoList[id].missionlist ) end Quote Share this post Link to post Share on other sites
BugsBunny 16 Report post Posted March 30, 2017 How about editing a Story quest reward? Quote Share this post Link to post Share on other sites
Leba 12 Report post Posted April 16, 2017 (edited) Great guide, but how are Quests "assigned" to NPCs? I mean, how does one make the Quest accepted at X NPC and then completed at Y NPC (or completed at X NPC, doesn't matter). Rookie question, but I haven't seen it explained anywhere in the Guide. Edit: Figured out the first part, but still clueless on how to make the quest finished at a different NPC. Edited April 16, 2017 by Leba Quote Share this post Link to post Share on other sites
Angelix 374 Report post Posted April 17, 2017 @LebaTry looking inside your server files and search for quests. There are some story quests which use what you want, get quest at X character and then complete at Y character. Such an example is this: DefineMission(206, "A Small Task", 203) MisBeginTalk("<t>Actually, I wanted To ask you To Investigate certain strange happenings In Shepherd Plains.<n><t>However, before That, I still have To Test you.<n><t>Go To <pArgent City Harbor> at(2277, 2831)and look for <bGeneral - William>. He will give you The next Task.") MisBeginCondition(NoRecord, 203) MisBeginCondition(NoMission, 203) MisBeginCondition(HasRecord, 200) MisBeginAction(AddMission, 203) MisCancelAction(ClearMission, 203) MisNeed(MIS_NEED_DESP, "Look for <bGeneral - William> In <pArgent City Harbor> at(2277, 2831)") MisHelpTalk("<t>Is There anymore questions? If not, please go and see <bGeneral William>, he has a Task for you.") MisResultCondition(AlwaysFailure) DefineMission(207, "A Small Task", 203, COMPLETE_SHOW) MisBeginCondition(AlwaysFailure) MisResultTalk("<t>Ah, Salvier Is a weird fella, sending us an unknown adventurer. Doesn't he Trust The Navy?<n><t>Come back when you're Ready. I have a job for you") MisResultCondition(NoRecord, 203) MisResultCondition(HasMission, 203) MisResultAction(ClearMission, 203) MisResultAction(SetRecord, 203) MisResultAction(AddExpAndType,2,875,875) Initially my guide is more centered towards the new functions of getting player kills. I did however add how to create the common quests since almost no one can create a functional quests so simple, but that was not my main focus. I never added the random quests, travel quests (like the one you asked for) and a few other that may be seen on story quests. Quote Share this post Link to post Share on other sites
Leba 12 Report post Posted April 17, 2017 (edited) 2 hours ago, Angelix said: @LebaTry looking inside your server files and search for quests. There are some story quests which use what you want, get quest at X character and then complete at Y character. Such an example is this: Oh, thanks so much. I was overthinking it and forgot I could just take a look at such a quest in the files. 2 hours ago, Angelix said: Initially my guide is more centered towards the new functions of getting player kills. I did however add how to create the common quests since almost no one can create a functional quests so simple, but that was not my main focus. I never added the random quests, travel quests (like the one you asked for) and a few other that may be seen on story quests. No worries, I understand what the point of your guide was and nothing I said was meant as criticism, your guide is titled "Create a Quest", so not including some finesses such as every type of quest, especially if unrelated to your guide, makes perfect sense. P.S. I was simply wondering how to make the quest finished at a different NPC, not about travel quests per se, but I guess the concept should pretty much the same with added condition(s), so thanks again! Edited April 17, 2017 by Leba Quote Share this post Link to post Share on other sites
Angelix 374 Report post Posted April 17, 2017 31 minutes ago, Leba said: P.S. I was simply wondering how to make the quest finished at a different NPC, not about travel quests per se, but I guess the concept should pretty much the same with added condition(s), so thanks again! The concept is the same. You have to make two script of quests, one that starts at NPC X and another to finish it at NPC Y, no added conditions or anything else. Take a look at the example I provided, it shows two "DefineMission" statements, meaning two quests, one should be in NPC X to start and another at NPC Y to finish. 1 Quote Share this post Link to post Share on other sites
MCHund 0 Report post Posted April 23, 2017 How do I add the function of having the NPC give an item at the end of the quest? Quote Share this post Link to post Share on other sites
Leba 12 Report post Posted April 23, 2017 9 minutes ago, MCHund said: How do I add the function of having the NPC give an item at the end of the quest? MisResultAction(GiveItem, ItemID, Amount, Quality) worked for me. Quote Share this post Link to post Share on other sites