• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!
  • 2026 staff recruitment is open! Check it out and consider applying!

NPC Advanced Quests Library - discussion before release

Gesior.pl

Mega Noob&LOL 2012
Senator
Joined
Sep 18, 2007
Messages
3,589
Solutions
140
Reaction score
4,688
Location
Poland
GitHub
gesior
PLAN CHANGED

It will be WWW editor to make quest NPCs. Read my posts in this thread.

These are things that my story writter asked me on MSN and which are possible to make with that NPC maker:
- [not ready yet in alpha version] NPC can write few lines of text between questions, so you can write long stories
- NPC can give different missions to players that pass other requests config [for example other first mission for 100 sorc and other for 100 knight and no mission for others]
 
Last edited:
Hmm I understnad so far you want to simplify syntax or get bunch of quests in one place. I can assure you its kind of misstake beaocsue when you want to add many many quests you start to be confused about what is what. But I came up with nice solution. Look

Mob%20brain.png


Circles represent npc, and squares a set of avaible tasks. But lets say we want to make some connections between missions that some other npc holds, yea we can use storages and after 100th quest we will forget what it should be connected to. So I think we should think of better solution for what you wanna do Gesior. Let me suggest some pseudo code idea.

I think that quest should consist of some clases
Npc -> Holds questLines keywords, check if we made a task and set flag if we did
Task -> holds flag set of mission, requirements to start task, rewards
TaskHandler -> holds all tasks with their names.
Flags -> a simple flag handler.

I think if you are able to code this it makes code much easier and intuituinal for ppl, also its harder to make misstake than in your lib -> if its sotred in one array.. sooner or later you will miss this one magic comma ^^

I made a library for that already but I would have to improve that so maybe I will show some sample of it :

Code:
	local Aldo = Npc:new("Lumberjack Trogg Nuggak")
    LumberjackingQuest = Mission:new("Lumberjacking Quest",5002) --one storage for all tasks
	--Mission lumbering
	LumberjackingQuestFlags = { --setrewards and prioces
		[1] = LumberjackingQuest:addFlag("FLAG_GET_FIRST_TASK"),
		[2] =LumberjackingQuest:addFlag("FLAG__BRING_300_WOOD",{neededflags = {"FLAG_GET_FIRST_TASK"}}):addRewards(
					{exp = 30000}, --reward if flag is set to player.
					{item = {id = 13985, amount = 20}},

					{rewardsContainer = 1987}
					):addRequirements( -- what is required to set this flag., later it might be flag from other quest xD
						{item ={id = 5901, amount = 350}}									
								),
		[3] =LumberjackingQuest:addFlag("FLAG_GET_SECOND_TASK",{neededflags = {"FLAG__BRING_300_WOOD"}}),
		
		[4] =LumberjackingQuest:addFlag("FLAG__BRING_700_WOOD",{neededflags = {"FLAG_GET_SECOND_TASK"}}):addRewards(
					{exp = 50000},
					{item = {id = 13986, amount = 1}},
					{rewardsContainer = 1987}
					):addRequirements(
						{item ={id = 5901, amount = 700}}									
								),
		[5] =LumberjackingQuest:addFlag("FLAG_GET_THIRD_TASK",{neededflags = {"FLAG__BRING_700_WOOD"}}),
		[6] =LumberjackingQuest:addFlag("FLAG__BRING_1500_WOOD",{neededflags = {"FLAG_GET_THIRD_TASK"}}):addRewards(
					{exp = 80000},
					{item = {id = 13987, amount = 1}},
					{rewardsContainer = 1987}
					):addRequirements(
						{item ={id = 5901, amount = 1500}}									
								),
	}

Later on I define questlines, message and callbacks. I will rewrite it and maybe share here too. Cheers.
 
@tarjei
I thought about website with graphic interface to make quests.. if there are still otses that need advanced quests, not only shit evos.
 
I could help you with that, it should be that hard.. I could devepe more this library of mine and show you my progress on it. If you find it usefull you could post it or whatever. :)
This or another way, I think that making those missions this way might be confusing when it comes to edit it. Just my opinion.
 
Idea from first post was good, but I think it will be easier to finish/upgrade/update tarjei's code.

I will continue my second idea. Website to make quest NPCs.
By graphic interface I meant something like that:
36r6OCR.png

(now weird colors to test if CSS is ok)
User can make some missions, in each he can add some texts, for each text he can set few answers, to each answer he can add some 'words' (for which NPC react) and some requirements that player must pass to continue with that 'answer'.
- If any requirements test fail it will show configured (in this requirement) text and do 'something' (list of possibile actions [one or few]).
- If player pass all tests, it will do 'something' (you choose it on website, by default 'go to next text').
When you finish all you can 'export' NPC to format which will let you import it again on www and edit that NPC or save as '.lua' NPC file [of course code will be ugly (but optimized), but it doesn't matter when you edit NPC on www]
 
I did small update. Current version of interface you can check here:
NPC Quests
When I finish it, I will write PHP code to generate LUA code.

EDIT:
First code generated by alpha version of code generator:
Code:
	local missionID = getCreatureStorage(cid, 123)
	local talkState = talkStates[cid]
	if(missionID == 0) then
		if(talkState == 0) then
			if(messageContains(msg, "yes") or messageContains(msg, "ok")) then
				if(not (getPlayerItemCount(cid, 1234) >= 3)) then
				end
			elseif(messageContains(msg, "no") or messageContains(msg, "don't")) then
			end
		elseif(talkState == 1) then
			if(messageContains(msg, "ye") or messageContains(msg, "of course")) then
			elseif(messageContains(msg, "no way") or messageContains(msg, "fuck\"you")) then
			end
		end
	end

EDIT 2:
another code from generator:
LUA:
	local missionID = getCreatureStorage(cid, 123)
	local talkState = talkStates[getPlayerGUID(cid)]
	if(missionID == 0) then
		if(talkState == 0) then
			if(messageContains(msg, "0.0.0.yes") or messageContains(msg, "0.0.0.mission")) then
				talkStates[getPlayerGUID(cid)] = 1
				selfSay("0.1._ can you bring me item 333? {yes}?", cid)
				return true
			end
		elseif(talkState == 1) then
			if(messageContains(msg, "0.1.0.e") or messageContains(msg, "0.1.0.of course")) then
				talkStates[getPlayerGUID(cid)] = 1
				doCreatureSetStorage(cid, 123, 1)
				selfSay("1.1._ do you have item 333 with you? {ye}?", cid)
				return true
			elseif(messageContains(msg, "0.1.1.no way") or messageContains(msg, "0.1.1.fuck\"you")) then
				selfSay("0.1.1.answer.Come back when you will be interested.", cid)
				talkStates[getPlayerGUID(cid)] = 1
				return true
			end
		end
	end
	if(missionID == 1) then
		if(talkState == 0) then
			if(messageContains(msg, "1.0.0.yes") or messageContains(msg, "1.0.0.mission") or messageContains(msg, "1.0.0.some shits")) then
				talkStates[getPlayerGUID(cid)] = 1
				selfSay("1.1._ do you have item 333 with you? {ye}?", cid)
				return true
			end
		elseif(talkState == 1) then
			if(messageContains(msg, "1.1.0.ye") or messageContains(msg, "1.1.0.of course")) then
				if(not (getPlayerItemCount(cid, 333) >= 1)) then
					selfSay("1.1.0.failanswer.You do not have item 333.", cid)
					talkStates[getPlayerGUID(cid)] = 1
					return true
				end
				selfSay("1.1.0.answer.Mission done. No more missions gzzz.", cid)
				return true
			elseif(messageContains(msg, "1.1.1.no way") or messageContains(msg, "1.1.1.fuck\"you")) then
				selfSay("1.1.1.answer.Come back when you will have item 333.", cid)
				talkStates[getPlayerGUID(cid)] = 1
				return true
			end
		end
	end
end
 
Last edited:
LUA:
local SampleQuest = Quest:new("LumberJacking")
	Aldo = Npc:new("Lumberjack Trogg Nuggak")
    LumberjackingQuest = Mission:new("Lumberjacking Quest",5004, SampleQuest)
	
	
	--Mission lumbering
	LumberjackingQuestFlags = { --setrewards and prioces
		[1] = LumberjackingQuest:addFlag("FLAG_GET_FIRST_TASK"):addState("So you have a task to bring a wood to NPC")
		),
		[2] =LumberjackingQuest:addFlag("FLAG__BRING_300_WOOD",{}):addRewards(
					{exp = 30000},
					{item = {id = 13985, amount = 20}},

					{rewardsContainer = 1987}
					):addRequirements(
						{item ={id = 5901, amount = 35}},
						{flags = {"FLAG_GET_FIRST_TASK"}},
								
					):addState("You have  broughtng wood for NPC. You can start next Mission. Cya.")
	}
I think its way easier to script by yourself using lib like this one I recently made : P Yoi wont need talkstates, one storage per mission, automaticly generate questlog (you just need to put message) Isnt it like in heaven? :D
 
Where can I setup words that player must say to accept/deny mission?
Is it possible to make NPC that has mission that require different things from different vocations/levels? Is it possible to add few missions that player can do in order that he wants, like: Do you want start mission {something}, {second}, {arena kill}?

Can you send me code?
It looks very nice, but only if you want make simple missions.
Try to describe in LUA something like this:
EDpPb9P.png


Contact
GG: 31166049
Skype: phoowned ([email protected])
MSN: [email protected]
 
I made something like this some time ago. I gave up on it, not worth it.
 
Ok Gesior I will contact you asap. Im still working on keywordhabdler using existing lib (someone made that already so why should we sweat XD Anywy it will be flathering using release things and prove someone learns on others works ^^)

Anyways , Gesior you will get my point when you see whole lib. What you presented on pic willbe entirely possible, I just have to make it more flexible.
 
Another code from generator, now with 'hello' msges:
LUA:
function npcGreet(cid)
	if(cid ~= 0) then
		NPCtalkState[getPlayerGUID(cid)] = 0
		if(getCreatureStorage(cid, 123) == -1) then
			doCreatureSetStorage(cid, 123, 0)
		end
		npcHandler:addFocus(cid)
		local missionID = getCreatureStorage(cid, 123)
		if(missionID == 0) then
			npcSay("0.0._ hello. mission? {yes}?")
			npcSay("0.0._ hello. mission? {yes}?", cid)
			return false
		end
		if(missionID == 1) then
			npcSay("1.0._ hello. are you here because you done {mission} ? {yes}?")
			npcSay("1.0._ hello. are you here because you done {mission} ? {yes}?", cid)
			return false
		end
	end
	return false
end
npcHandler:setCallback(CALLBACK_GREET, npcGreet)

function npcTalkAboutMission(cid, type, msg)
	if(not npcHandler:isFocused(cid)) then
		return false
	end
	local missionID = getCreatureStorage(cid, 123)
	local talkState = talkStates[getPlayerGUID(cid)]
	if(missionID == 0) then
		if(talkState == 0) then
			if(messageContains(msg, "0.0.0.yes") or messageContains(msg, "0.0.0.mission")) then
				talkStates[getPlayerGUID(cid)] = 1
				selfSay("0.1._ can you bring me item 333? {yes}?", cid)
				return true
			end
		elseif(talkState == 1) then
			if(messageContains(msg, "0.1.0.yes") or messageContains(msg, "0.1.0.of course")) then
				talkStates[getPlayerGUID(cid)] = 1
				doCreatureSetStorage(cid, 123, 1)
				selfSay("1.1._ do you have item 333 with you? {ye}?", cid)
				return true
			elseif(messageContains(msg, "0.1.1.no way") or messageContains(msg, "0.1.1.fuck\"you")) then
				selfSay("0.1.1.answer.Come back when you will be interested.", cid)
				talkStates[getPlayerGUID(cid)] = 0
				return true
			end
		end
	end
	if(missionID == 1) then
		if(talkState == 0) then
			if(messageContains(msg, "1.0.0.yes") or messageContains(msg, "1.0.0.mission") or messageContains(msg, "1.0.0.some shits")) then
				talkStates[getPlayerGUID(cid)] = 1
				selfSay("1.1._ do you have item 333 with you? {ye}?", cid)
				return true
			end
		elseif(talkState == 1) then
			if(messageContains(msg, "1.1.0.ye") or messageContains(msg, "1.1.0.of course")) then
				if(not (getPlayerItemCount(cid, 333) >= 1)) then
					selfSay("1.1.0.failanswer.You do not have item 333.", cid)
					talkStates[getPlayerGUID(cid)] = 0
					return true
				end
				selfSay("1.1.0.answer.Mission done. No more missions gzzz.", cid)
				return true
			elseif(messageContains(msg, "1.1.1.no way") or messageContains(msg, "1.1.1.fuck\"you")) then
				selfSay("1.1.1.answer.Come back when you will have item 333.", cid)
				talkStates[getPlayerGUID(cid)] = 0
				return true
			end
		end
	end
end
I hope I will have time to finish script this weekend.
 
@up
Yes

For tests I generate LUA based on config from PHP. If it will work good I will write javascript code to parse graphic editor data into one big array and send to PHP script to generate LUA code.

Current version of my PHP code, not clean :$ , but it won't be public/editable code, so doesn't matter.
PHP:
<?PHP
$npc['storage'] = 123;
$npc['storageKill'] = 124;

$missions = array();

$mission = array();
$mission['id'] = 0;
$mission['name'] = 'NaMe';
$mission['comment'] = 'CoMMeNt';

$mission['text'] = array();
$mission['text'][0] = array();
$mission['text'][0]['text'] = '0.0._ hello. mission? {yes}?';

$mission['text'][0]['answers'] = array();

$mission['text'][0]['answers'][0] = array();
$mission['text'][0]['answers'][0]['words'] = array();
$mission['text'][0]['answers'][0]['words'][0] = '0.0.0.yes';
$mission['text'][0]['answers'][0]['words'][1] = '0.0.0.mission';
$mission['text'][0]['answers'][0]['requirements'] = array();
$mission['text'][0]['answers'][0]['actions'] = array();
$mission['text'][0]['answers'][0]['actions'][0] = array();
$mission['text'][0]['answers'][0]['actions'][0]['type'] = '2';
$mission['text'][0]['answers'][0]['actions'][0]['params'] = array();


$mission['text'][1] = array();
$mission['text'][1]['text'] = '0.1._ can you bring me item 333? {yes}?';

$mission['text'][1]['answers'] = array();

$mission['text'][1]['answers'][0] = array();
$mission['text'][1]['answers'][0]['words'] = array();
$mission['text'][1]['answers'][0]['words'][0] = '0.1.0.yes';
$mission['text'][1]['answers'][0]['words'][1] = '0.1.0.of course';
$mission['text'][1]['answers'][0]['requirements'] = array();
$mission['text'][1]['answers'][0]['actions'] = array();
$mission['text'][1]['answers'][0]['actions'][0] = array();
$mission['text'][1]['answers'][0]['actions'][0]['type'] = '4';
$mission['text'][1]['answers'][0]['actions'][0]['params'] = array();

$mission['text'][1]['answers'][1] = array();
$mission['text'][1]['answers'][1]['words'] = array();
$mission['text'][1]['answers'][1]['words'][0] = '0.1.1.no way';
$mission['text'][1]['answers'][1]['words'][1] = '0.1.1.fuck"you';
$mission['text'][1]['answers'][1]['requirements'] = array();
$mission['text'][1]['answers'][1]['actions'] = array();
$mission['text'][1]['answers'][1]['actions'][0] = array();
$mission['text'][1]['answers'][1]['actions'][0]['type'] = '1';
$mission['text'][1]['answers'][1]['actions'][0]['params'] = array();
$mission['text'][1]['answers'][1]['actions'][0]['params'][1] = '0.1.1.answer.Come back when you will be interested.';
$mission['text'][1]['answers'][1]['actions'][1] = array();
$mission['text'][1]['answers'][1]['actions'][1]['type'] = '8';
$mission['text'][1]['answers'][1]['actions'][1]['params'] = array();

$missions[0] = $mission;



$mission = array();
$mission['id'] = 1;
$mission['name'] = 'NaMe2';
$mission['comment'] = 'CoMMeNt2';

$mission['text'] = array();
$mission['text'][0] = array();
$mission['text'][0]['text'] = '1.0._ hello. are you here because you done {mission} ? {yes}?';

$mission['text'][0]['answers'] = array();

$mission['text'][0]['answers'][0] = array();
$mission['text'][0]['answers'][0]['words'] = array();
$mission['text'][0]['answers'][0]['words'][0] = '1.0.0.yes';
$mission['text'][0]['answers'][0]['words'][1] = '1.0.0.mission';
$mission['text'][0]['answers'][0]['words'][2] = '1.0.0.some shits';
$mission['text'][0]['answers'][0]['requirements'] = array();
$mission['text'][0]['answers'][0]['actions'] = array();
$mission['text'][0]['answers'][0]['actions'][0] = array();
$mission['text'][0]['answers'][0]['actions'][0]['type'] = '2';
$mission['text'][0]['answers'][0]['actions'][0]['params'] = array();;



$mission['text'][1] = array();
$mission['text'][1]['text'] = '1.1._ do you have item 333 with you? {ye}?';

$mission['text'][1]['answers'] = array();

$mission['text'][1]['answers'][0] = array();
$mission['text'][1]['answers'][0]['words'] = array();
$mission['text'][1]['answers'][0]['words'][0] = '1.1.0.ye';
$mission['text'][1]['answers'][0]['words'][1] = '1.1.0.of course';
$mission['text'][1]['answers'][0]['requirements'] = array();
$mission['text'][1]['answers'][0]['requirements'][0] = array();
$mission['text'][1]['answers'][0]['requirements'][0]['type'] = '6';
$mission['text'][1]['answers'][0]['requirements'][0]['params'] = array();
$mission['text'][1]['answers'][0]['requirements'][0]['params'][1] = '333';
$mission['text'][1]['answers'][0]['requirements'][0]['params'][2] = '>=';
$mission['text'][1]['answers'][0]['requirements'][0]['params'][3] = '1';
$mission['text'][1]['answers'][0]['requirements'][0]['failActions'] = array();
$mission['text'][1]['answers'][0]['requirements'][0]['failActions'][0] = array();
$mission['text'][1]['answers'][0]['requirements'][0]['failActions'][0]['type'] = '1';
$mission['text'][1]['answers'][0]['requirements'][0]['failActions'][0]['params'] = array();
$mission['text'][1]['answers'][0]['requirements'][0]['failActions'][0]['params'][1] = '1.1.0.failanswer.You do not have item 333.';
$mission['text'][1]['answers'][0]['requirements'][0]['failActions'][1] = array();
$mission['text'][1]['answers'][0]['requirements'][0]['failActions'][1]['type'] = '8';
$mission['text'][1]['answers'][0]['requirements'][0]['failActions'][1]['params'] = array();
$mission['text'][1]['answers'][0]['actions'] = array();
$mission['text'][1]['answers'][0]['actions'][0] = array();
$mission['text'][1]['answers'][0]['actions'][0]['type'] = '1';
$mission['text'][1]['answers'][0]['actions'][0]['params'] = array();
$mission['text'][1]['answers'][0]['actions'][0]['params'][1] = '1.1.0.answer.Mission done. No more missions gzzz.';
// add reward
// 

$mission['text'][1]['answers'][1] = array();
$mission['text'][1]['answers'][1]['words'] = array();
$mission['text'][1]['answers'][1]['words'][0] = '1.1.1.no way';
$mission['text'][1]['answers'][1]['words'][1] = '1.1.1.fuck"you';
$mission['text'][1]['answers'][1]['requirements'] = array();
$mission['text'][1]['answers'][1]['actions'] = array();
$mission['text'][1]['answers'][1]['actions'][0] = array();
$mission['text'][1]['answers'][1]['actions'][0]['type'] = '1';
$mission['text'][1]['answers'][1]['actions'][0]['params'] = array();
$mission['text'][1]['answers'][1]['actions'][0]['params'][1] = '1.1.1.answer.Come back when you will have item 333.';
$mission['text'][1]['answers'][1]['actions'][1] = array();
$mission['text'][1]['answers'][1]['actions'][1]['type'] = '8';
$mission['text'][1]['answers'][1]['actions'][1]['params'] = array();







$missions[1] = $mission;
$nl = '<br />';
$tab = '	';
function t($times)
{
	$ret = '';
	for($i = 0; $i < $times; $i++)
	{
		$ret .= '	';
	}
	return $ret;
}

function printActions($missions, $actions, $missionID, $textID, $answerID, $tabCount)
{
	foreach($actions as $action)
	{
	// zmianiec next na dane ID
	}
	$realActions = array();
	foreach($actions as $action)
	{
//var_dump($action);
		switch($action['type'])
		{
			case 1: // say
				echo t($tabCount) . 'selfSay("' . str_replace('"', '\"', $action['params'][1]) . '", cid)' . $GLOBALS['nl'];
				break;
			case 2: // Go to next text
				echo t($tabCount) . 'talkStates[getPlayerGUID(cid)] = ' . ($textID+1) . $GLOBALS['nl'];
				echo t($tabCount) . 'selfSay("' . str_replace('"', '\"', $missions[$missionID]['text'][($textID+1)]['text']) . '", cid)' . $GLOBALS['nl'];
				// show text
				break;
			case 3: // Go to next mission
				echo t($tabCount) . 'talkStates[getPlayerGUID(cid)] = 1' . $GLOBALS['nl'];
				echo t($tabCount) . 'doCreatureSetStorage(cid, ' . $GLOBALS['npc']['storage'] . ', ' . ($missionID+1) . ')' . $GLOBALS['nl'];
				break;
			case 4: // Go to next mission and show it's text
				echo t($tabCount) . 'talkStates[getPlayerGUID(cid)] = 1' . $GLOBALS['nl'];
				echo t($tabCount) . 'doCreatureSetStorage(cid, ' . $GLOBALS['npc']['storage'] . ', ' . ($missionID+1) . ')' . $GLOBALS['nl'];
				echo t($tabCount) . 'selfSay("' . str_replace('"', '\"', $missions[($missionID+1)]['text'][1]['text']) . '", cid)' . $GLOBALS['nl'];
				break;
			case 5: // Go to text <X_1> and show text // in same mission
				echo t($tabCount) . 'talkStates[getPlayerGUID(cid)] = ' . $action['params'][1] . $GLOBALS['nl'];
				echo t($tabCount) . 'selfSay("' . str_replace('"', '\"', $missions[$missionID]['text'][$action['params'][1]]['text']) . '", cid)' . $GLOBALS['nl'];
				break;
			case 6: // Go to mission <X_1> <X_2> // mission X, text X
				echo t($tabCount) . 'doCreatureSetStorage(cid, ' . $GLOBALS['npc']['storage'] . ', ' . $action['params'][1] . ')' . $GLOBALS['nl'];
				echo t($tabCount) . 'talkStates[getPlayerGUID(cid)] = ' . $action['params'][2] . $GLOBALS['nl'];
				break;
			case 7: // Go to mission <X_1> <X_2> and show text// mission X, text X
				echo t($tabCount) . 'doCreatureSetStorage(cid, ' . $GLOBALS['npc']['storage'] . ', ' . $action['params'][1] . ')' . $GLOBALS['nl'];
				echo t($tabCount) . 'talkStates[getPlayerGUID(cid)] = ' . $action['params'][2] . $GLOBALS['nl'];
				echo t($tabCount) . 'selfSay("' . str_replace('"', '\"', $missions[$action['params'][1]]['text'][$action['params'][2]]['text']) . '", cid)' . $GLOBALS['nl'];
				break;
			case 8: // Go to start of NPC // talkstate = 1
				echo t($tabCount) . 'talkStates[getPlayerGUID(cid)] = 0' . $GLOBALS['nl'];
				break;
			case 9: //
				
				break;
		}
	}
	echo t($tabCount) . 'return true' . $GLOBALS['nl'];
}
/*
actionsAvailable[0] = Array("None", "");
actionsAvailable[1] = Array("Say", '<input type="type" value="" name="param1" />');
actionsAvailable[2] = Array("Go to next text", ""); // wait for answer from next 'text'
actionsAvailable[3] = Array("Go to next mission", ""); // go to next mission
actionsAvailable[4] = Array("Go to next mission and show text", ""); // go to next mission and show text
actionsAvailable[5] = Array("Go to text and show it's text", '<input type="type" value="1" name="param1" />'); // go to text X and show it's text
actionsAvailable[6] = Array("Go to mission", 'MissionID <input type="type" value="" name="param1" />, TextID <input type="type" value="1" name="param2" />'); // go to mission X, text X
actionsAvailable[7] = Array("Go to mission and show text", 'MissionID <input type="type" value="" name="param1" />, TextID <input type="type" value="1" name="param2" />'); // go to mission X, text X and show text
actionsAvailable[8] = Array("Go to start of NPC", ""); // talkstate = 1
*/
echo '<pre>';
echo t(0) . 'function npcGreet(cid)' . $nl;
echo t(1) . 'if(cid ~= 0) then' . $nl;
echo t(2) . 'NPCtalkState[getPlayerGUID(cid)] = 0' . $nl;
echo t(2) . 'if(getCreatureStorage(cid, ' . $npc['storage'] . ') == -1) then' . $nl;
echo t(3) . 'doCreatureSetStorage(cid, ' . $npc['storage'] . ', 0)' . $nl;
echo t(2) . 'end' . $nl;
echo t(2) . 'npcHandler:addFocus(cid)' . $nl;
echo t(2) . 'local missionID = getCreatureStorage(cid, ' . $npc['storage'] . ')' . $nl;
foreach($missions as $mission)
{
	echo t(2) . 'if(missionID == ' . $mission['id'] . ') then' . $nl;
	echo t(3) . 'npcSay("' . str_replace('"', '\"', $mission['text'][0]['text']) . '")' . $nl;
	echo t(3) . 'npcSay("' . str_replace('"', '\"', $mission['text'][0]['text']) . '", cid)' . $nl;
	echo t(3) . 'return false' . $nl;
	echo t(2) . 'end' . $nl;
}
echo t(1) . 'end' . $nl;
echo t(1) . 'return false' . $nl;
echo t(0) . 'end' . $nl;
echo t(0) . 'npcHandler:setCallback(CALLBACK_GREET, npcGreet)' . $nl . $nl;

echo 'function npcTalkAboutMission(cid, type, msg)' . $nl;
echo t(1) . 'if(not npcHandler:isFocused(cid)) then' . $nl;
echo t(2) . 'return false' . $nl;
echo t(1) . 'end' . $nl;
echo t(1) . 'local missionID = getCreatureStorage(cid, ' . $npc['storage'] . ')' . $nl;
echo t(1) . 'local talkState = talkStates[getPlayerGUID(cid)]' . $nl;

foreach($missions as $mission)
{
	echo t(1) . 'if(missionID == ' . $mission['id'] . ') then' . $nl;
	//echo '-----------';
	foreach($mission['text'] as $textID => $text)
	{
		echo t(2) . (($textID > 0) ? 'else' : '') . 'if(talkState == ' . $textID . ') then' . $nl;
		foreach($text['answers'] as $answerID => $answer)
		{
			echo t(3) . (($answerID > 0) ? 'else' : '') . 'if(';
			$answerWords = array();
			foreach($answer['words'] as $word)
				$answerWords[] = 'messageContains(msg, "' . str_replace('"', '\"', $word) . '")';
			echo implode(' or ', $answerWords) . ') then' . $nl;

			$anyVocation = false;
			foreach($answer['requirements'] as $require)
			{
				switch($require['type'])
				{
					case 1: // level
						echo t(4) . 'if(not (getPlayerLevel(cid) ' . $require['params'][1] . ' ' . $require['params'][2] . ')) then' . $nl;
						printActions($missions, $require['failActions'], $mission['id'], $textID, $answerID, 5);
						echo t(4) . 'end' . $nl;
						break;
					case 2: // magic level
						echo t(4) . 'if(not (getPlayerMagLevel(cid) ' . $require['params'][1] . ' ' . $require['params'][2] . ')) then' . $nl;
						printActions($missions, $require['failActions'], $mission['id'], $textID, $answerID, 5);
						echo t(4) . 'end' . $nl;
						break;
					case 3: // skill level
						echo t(4) . 'if(not (getPlayerSkillLevel(cid, ' . $require['params'][1] . ') ' . $require['params'][2] . ' ' . $require['params'][3] . ')) then' . $nl;
						printActions($missions, $require['failActions'], $mission['id'], $textID, $answerID, 5);
						echo t(4) . 'end' . $nl;
						break;
						// todo all below
					case 4: // vocation is
						$vocations = explode(';', $require['params'][1]);
						echo t(4) . 'if(not (getPlayerMagLevel(cid) ' . $require['params'][1] . ' ' . $require['params'][2] . ')) then' . $nl;
						printActions($missions, $require['failActions'], $mission['id'], $textID, $answerID, 5);
						echo t(4) . 'end' . $nl;
						break;
					case 5: // vocation is not
						echo t(4) . 'if(not (getPlayerMagLevel(cid) ' . $require['params'][1] . ' ' . $require['params'][2] . ')) then' . $nl;
						printActions($missions, $require['failActions'], $mission['id'], $textID, $answerID, 5);
						echo t(4) . 'end' . $nl;
						break;
					case 6: // item count
						echo t(4) . 'if(not (getPlayerItemCount(cid, ' . $require['params'][1] . ') ' . $require['params'][2] . ' ' . $require['params'][3] . ')) then' . $nl;
						printActions($missions, $require['failActions'], $mission['id'], $textID, $answerID, 5);
						echo t(4) . 'end' . $nl;
						break;
					case 7: // item slot
						echo t(4) . 'if(not (getPlayerItemCount(cid, ' . $require['params'][1] . ') ' . $require['params'][2] . ' ' . $require['params'][3] . ')) then' . $nl;
						printActions($missions, $require['failActions'], $mission['id'], $textID, $answerID, 5);
						echo t(4) . 'end' . $nl;
						break;
				}
			}
			printActions($missions, $answer['actions'], $mission['id'], $textID, $answerID, 4);
			//getPlayerSkillLevel(cid, skill
			//getPlayerVocation(cid)
			/*
	requirementsAvailable[0] = Array("None", "");
	requirementsAvailable[1] = Array("Level", '<select name="param1">' + compareNumberOptions + '</select><input type="text" name="param2" value="0" />');
	requirementsAvailable[2] = Array("Magic Level", '<select name="param1">' + compareNumberOptions + '</select><input type="text" name="param2" value="0" />');
	requirementsAvailable[3] = Array("Skill Level", '<select name="param1">' + skillOptions + '</select><select name="param2">' + compareNumberOptions + '</select><input type="text" name="param3" value="0" />');
	requirementsAvailable[4] = Array("Vocation IS", '<select name="param1">' + compareNumberOptions + '</select><input type="text" name="param2" value="0" />');
	requirementsAvailable[5] = Array("Vocation IS NOT", '<select name="param1">' + compareNumberOptions + '</select><input type="text" name="param2" value="0" />');
	requirementsAvailable[6] = Array("Item Count", 'Item ID: <input type="text" name="param1" size="5" value="0" /> Count: <select name="param2">' + compareNumberOptions + '</select><input type="text" name="param3" value="0" />');
	requirementsAvailable[7] = Array("Item Slot", 'Item Slot <select name="param1">' + slotOptions + '</select> ItemID <input type="text" name="param2" size="5" value="0" /> Attributes <input type="text" size="60" name="param3" value="" />');
	*/
			if($answerID+1 == count($text['answers']))
			{
				echo t(3) . 'end' . $nl;
			}
		}
		if($textID+1 == count($mission['text']))
		{
			echo t(2) . 'end' . $nl;
		}
	}
	echo t(1) . 'end' . $nl;
}
echo t(0) . 'end' . $nl;
echo '</pre>';
?>

EDIT:
First chat with NPC. I take from him mission and then tell him that I got item that he requested ( I lie ):
19:05 Ohyeah [18]: hi
19:05 Z: 0.0._ hello. mission? yes?
19:06 Ohyeah [18]: 0.0.0.yes
19:06 Z: 0.1._ can you bring me item 333? yes?
19:06 Ohyeah [18]: 0.1.1.no way
19:06 Z: 0.1.1.answer.Come back when you will be interested.
19:06 Ohyeah [18]: 0.0.0.yes
19:06 Z: 0.1._ can you bring me item 333? yes?
19:06 Ohyeah [18]: 0.1.0.yes
19:06 Z: 1.1._ do you have item 333 with you? ye?
19:07 Ohyeah [18]: 1.1.0.ye
19:07 Z: 1.1.0.failanswer.You do not have item 333.

NPC code from generator:
LUA:
local keywordHandler = KeywordHandler:new()
local npcHandler = NpcHandler:new(keywordHandler)
NpcSystem.parseParameters(npcHandler)
function onCreatureAppear(cid) npcHandler:onCreatureAppear(cid) end
function onCreatureDisappear(cid) npcHandler:onCreatureDisappear(cid) end
function onCreatureSay(cid, type, msg) npcHandler:onCreatureSay(cid, type, msg) end
function onThink() npcHandler:onThink() end

local talkStates = {}

function npcGreet(cid)
	if(cid ~= 0) then
		talkStates[getPlayerGUID(cid)] = 0
		if(getCreatureStorage(cid, 123) == -1) then
			doCreatureSetStorage(cid, 123, 0)
		end
		npcHandler:addFocus(cid)
		local missionID = getCreatureStorage(cid, 123)
		if(missionID == 0) then
			selfSay("0.0._ hello. mission? {yes}?")
			selfSay("0.0._ hello. mission? {yes}?", cid)
			return false
		end
		if(missionID == 1) then
			selfSay("1.0._ hello. are you here because you done {mission} ? {yes}?")
			selfSay("1.0._ hello. are you here because you done {mission} ? {yes}?", cid)
			return false
		end
	end
	return false
end
npcHandler:setCallback(CALLBACK_GREET, npcGreet)

function npcTalkAboutMission(cid, type, msg)
	if(not npcHandler:isFocused(cid)) then
		return false
	end
	local missionID = getCreatureStorage(cid, 123)
	local talkState = talkStates[getPlayerGUID(cid)]
	if(missionID == 0) then
		if(talkState == 0) then
			if(npcMakerMessageContains(msg, "0.0.0.yes") or npcMakerMessageContains(msg, "0.0.0.mission")) then
				talkStates[getPlayerGUID(cid)] = 1
				selfSay("0.1._ can you bring me item 333? {yes}?", cid)
				return true
			end
		elseif(talkState == 1) then
			if(npcMakerMessageContains(msg, "0.1.0.yes") or npcMakerMessageContains(msg, "0.1.0.of course")) then
				talkStates[getPlayerGUID(cid)] = 1
				doCreatureSetStorage(cid, 123, 1)
				selfSay("1.1._ do you have item 333 with you? {ye}?", cid)
				return true
			elseif(npcMakerMessageContains(msg, "0.1.1.no way") or npcMakerMessageContains(msg, "0.1.1.fuck\"you")) then
				selfSay("0.1.1.answer.Come back when you will be interested.", cid)
				talkStates[getPlayerGUID(cid)] = 0
				return true
			end
		end
	end
	if(missionID == 1) then
		if(talkState == 0) then
			if(npcMakerMessageContains(msg, "1.0.0.yes") or npcMakerMessageContains(msg, "1.0.0.mission") or npcMakerMessageContains(msg, "1.0.0.some shits")) then
				talkStates[getPlayerGUID(cid)] = 1
				selfSay("1.1._ do you have item 333 with you? {ye}?", cid)
				return true
			end
		elseif(talkState == 1) then
			if(npcMakerMessageContains(msg, "1.1.0.ye") or npcMakerMessageContains(msg, "1.1.0.of course")) then
				if(not (getPlayerItemCount(cid, 333) >= 1)) then
					selfSay("1.1.0.failanswer.You do not have item 333.", cid)
					talkStates[getPlayerGUID(cid)] = 0
					return true
				end
				selfSay("1.1.0.answer.Mission done. No more missions gzzz.", cid)
				return true
			elseif(npcMakerMessageContains(msg, "1.1.1.no way") or npcMakerMessageContains(msg, "1.1.1.fuck\"you")) then
				selfSay("1.1.1.answer.Come back when you will have item 333.", cid)
				talkStates[getPlayerGUID(cid)] = 0
				return true
			end
		end
	end
end
npcHandler:setCallback(CALLBACK_MESSAGE_DEFAULT, npcTalkAboutMission)

function npcFarewell(cid)
	if(not npcHandler:isFocused(cid)) then
		return
	end
	npcHandler:releaseFocus(cid)
	selfSay("Bye!", cid)
	return false
end
npcHandler:setCallback(CALLBACK_FAREWELL, npcFarewell)

npcHandler:addModule(FocusModule:new())
 
Last edited:
Not what I'd thought, but that code is still pretty neat. Keep at it, good luck!
 
First NPC made in alpha version of editor:

7EERKG9.png



First code returned from PHP script:
gqjoHZl.png
 
Hello again, good job gesior, I was kinda thinking about my own lib, and I figured that XML provides most easiest syntax to understand.

XML:
<questline>
	<node keywords = "quest;task" response = "Some npc message">
		<requirement condition = "getPlayerLevel(cid) < 10 and |CANSETFLAG|:|FLAGNAME|">
		<callback>
				function(cid, message, keywords, parameters, node)
					print("Callback called when player said node keyword :D PARSER NICE!")
				end
		</callback>
		<setflag key="FLAG NAME"/>

		--Child Keyword
		<node keywords = "yes; sure" response = "Ok then I will give you this task">
			some free tedst
			<setflag key="FLAG NAME2"/>
		</node>
		
	</node>
</questline>
 
My NPC maker change part of website [with missions] into XHTML (jQuery), then send it by AJAX (jQuery) to PHP script which change XHTML to PHP array and then generate NPC LUA code :P

I've added 32 possible 'actions' in website editor (not all ready to generate LUA code in PHP script).

Code generated by PHP:
LUA:
				local tileItem = getTileItemById({x=67,y=56,z=456}, 3434)
				if(tileItem.uid > 0) then
					doRemoveItem(tileItem.uid)
				end
				local tmpItem = doCreateItemEx(4543)
				doItemSetAttribute(tmpItem, "name", "Something new!")
				doItemSetAttribute(tmpItem, "actionid", "123")
				doTileAddItemEx({x=78,y=67,z=567}, tmpItem)
				return true
from config:
Sb6BEpN.png


What 'requirements' are missing?
Except these which are in 'requirements' list I will add:
- check storage
- check kill mission

but what else you want check?
 
Back
Top