Jump to content

Understand Quest System


Recommended Posts

Here is a copy of a discussion I had some weeks ago with a guy on MSN. It will be formatted with time and enhanced when I got time. It was enough long to format it using MSN history...

 

GENERIC TO-KNOW THINGS

 

A quest is an instance (child) of a mother class, named Quest (in core side). Each quest inherits content of that superclass. Methods with "@Override" flag means they're using a method of that superclass. All methods for quests are stored in Quest.java so don't search anywhere else if you want to add or verify a method.

 

 

MAIN METHODS && OTHERS

 

Well, on any quest so far you got 2 methods, onAdvEvent() and onTalk(). If you haven't those 2 methods, your quest is just trash.

  • onAdvEvent() leads the behavior of HTM bypasses, it does only that = when you click on a link from an html linked to that quest, it will search on onAdvEvent if an event is registered. By convention, a HTM bypass event refers to the HTM you must open. This HTM will be opened even if no event is associated with that bypass (case of big monologues when you speak to a guy and he gives you 5 different HTMs, but nothing special happens).
  • onTalk() is the chat window behavior. It is mainly influenced by cond variable. That method controls HTMs view following conditions. "cond" variable is one of them, but it can be anything (player's level or race for exemple at startup will show you different HTM).
 

Following methods are often used, but not vital :

  • onKill() controls behavior about when you kill a mob. You can make it chatting, show an HTM, etc etc.
  • onSkillSee() allows to make tests about skills
  • onAggroRange() allows special events when you enter in aggro range of a monster (so far, I think it's only aggro based...)
  • More to list, you can check on Quest.java anyway
Those methods are supposed to send a String. That String is for HTMs sending, nothing more. If no HTM must be send, it must send "the default HTM" (case of vital methods) or "null" (cases of others methods where HTM isn't required).

 

 

CORE OF A QUEST

 

Methods explained higher are nothing if you don't register IDs of involved NPCs. This is made in the top up 'main' method (sorry i don't know the technic name), which refers to the quest itself.

 

Exemple for Q013:

 



public Q013_ParcelDelivery(int questId, String name, String descr)
{
super(questId, name, descr);
 
questItemIds = new int[] { PACKAGE };
 
addStartNpc(FUNDIN);
addTalkId(FUNDIN, VULCAN);
}


 

In that "method" you can see recurrent stuff :



super(questId, name, descr);


is always here don't touch that's all 

 



questItemIds = new int[] { PACKAGE };


It's the place where quest items are put. Those quest items WILL BE DELETED at quest end. So care about what you put (don't put things such as materials ( thread, iron ore, and so one) or even rewards.

 



addStartNpc(FUNDIN);
addTalkId(FUNDIN, VULCAN);


Those lines register following IDs in onTalk/onAdvEvent

 

So far there is nearly all time - 99% - one startnpc, and that startnpc got on addtalkid (else he's broken)

 

In top bottom of java quest you can see



public static void main(String[] args)
{
new Q013_ParcelDelivery(13, qn, "Parcel Delivery");
}


(13, qn, "Parcel Delivery")

 

  • That number MUST be the good quest one, else you will send the wrong quest logs to the client - imagine you write 6, you will send content of quest 6 in quest window...
  • qn refers to a variable seted at begin of the quest, which is the convention name of the quest
  • 3rd parameter is the ingame name of the quest, shown in client ; it is used if you got multiple quests on "quest section", and will show the quest name
 

"cond" VARIABLE / MISC VARIABLES.

 

EACH quest got 2 generic variables named "cond" and "state".

"cond" is used to call the good htm, and to show you the good log of the quest in INGAME quest window

"state" stores the quest state under 3 different values ; "created/started/completed". It is used for bigger check.

 

Those 2 generic variables are stored under "character_quests" mySQL table. Others variables can be created following the quest's needs.

 

 

HTM BYPASSES.

 

A HTM bypass is a sort of link you will find on HTMs. They are always build like that :

<a action="bypass -h Quest Q300_HuntingLetoLizardman 30126-03.htm">"I'll do it."</a>

  • That part never moves, it says that bypass is linked to Quest system.
  • That part is obviously the name of the quest ; in aCis i decided to convention it like that : QXXX_NameOfQuest
  • That part is the event itself ; by convention it is ALL TIME an htm ; in some rare cases, you can't do it (exemple of multichoices)
 

QUEST STATES.

 

A quest got 3 states for non repeatable quest, and 2 for repeatable. In order : CREATED, STARTED, and COMPLETED (COMPLETED is never reached in a repeatable quest).

 

  • CREATED is when the quest is still not STARTED ; aka you still didn't accept the quest (in old L2J IL writting style, it was cond == 0).
  • STARTED is when you accepted the quest (so in 100% of cases = sound + cond = 1) that state is ofc the most common
  • COMPLETED occurs only when a quest is non repeatable ; it is indirectly used by existQuest(true/false), so you will never see it activated except as a check to see if quest is already completed or not
 

Quests can understand following writting : st.isCreated() / st.isStarted() / st.isCompleted()

st refers to QuestState of the player.

 

 

exitQuest(boolean) method.

 

exitQuest(boolean repeatable):

  • if put to true (so repeatable), it will clean states and quest entry from database
  • if 0 (false), all is kept
 

  • Upvote 3
Link to comment
Share on other sites

I really love to read this kind of topics about how does it work and how to improve.I wish there would be more than few topics like this.

 

Gimme a subject and I will try to make it. This guide exists on my forums since 2011, in order to help people to understand how scripts work (as in that time I decided to move all quests from python to Java on aCis and I needed helping hands) but as it has only 660 views I decided to expand to "public" forums (even if, it is public on my forums).

 

I virtually can explain anything, except :

  • geoengine (or just the big lines)
  • MMOCore (didn't have to think about it / rework, as it works fine since years on L2J)
Edited by Tryskell
Link to comment
Share on other sites

He continued to teach, mate.

Thank you..

 

I am one of the few who will read it..

We all want them ready.. ;)

 

+1

Link to comment
Share on other sites

Nice one. But you can update that with informations about current l2j quests.

Like this:

public Q10323_TrainLikeItsReal()
{
super(10323, Q10323_TrainLikeItsReal.class.getSimpleName(), "Train Like It's Real");
addStartNpc(EVAIN);
addTalkId(HOLDEN, EVAIN, SHANNON);
addKillId(TRAINING_GOLEM);
addCondMaxLevel(MAX_LEVEL, "33464-05.htm");
addCondCompletedQuest(Q10322_SearchingForTheMysteriousPower.class.getSimpleName(), "33464-05.htm");
}
Edited by Snehulak
Link to comment
Share on other sites

Nice one. But you can update that with informations about current l2j quests.

Like this:

public Q10323_TrainLikeItsReal()
{
super(10323, Q10323_TrainLikeItsReal.class.getSimpleName(), "Train Like It's Real");
addStartNpc(EVAIN);
addTalkId(HOLDEN, EVAIN, SHANNON);
addKillId(TRAINING_GOLEM);
addCondMaxLevel(MAX_LEVEL, "33464-05.htm");
addCondCompletedQuest(Q10322_SearchingForTheMysteriousPower.class.getSimpleName(), "33464-05.htm");
}
This

addCondMaxLevel(MAX_LEVEL, "33464-05.htm");
addCondCompletedQuest(Q10322_SearchingForTheMysteriousPower.class.getSimpleName(), "33464-05.htm");
not necessarily define in this place.

 

This enough

		switch (st.getState())
		{
			case STATE_CREATED:
				htmltext = (player.getLevel() < 2) ? "30048-01.htm" : "30048-02.htm";
				break;
			
			case STATE_STARTED:
				
				...
				
				break;
			
			case STATE_COMPLETED:
				htmltext = getAlreadyCompletedMsg();
				break;
		}
Edited by Rootware
Link to comment
Share on other sites

addCondCompletedQuest(QXX_BLALBALBALBLA.class.getSimpleName(), "xxx.htm");

Its more easier for newbies to understand and get into how quest engine is working now. I don't like old way where you had add check into CREATED. Now you just put that into addCondCompletedQuest and that's all.

 

Old way check...

qs = player.getQuestState(QXXX_XXX.class.getSimpleName());
if (qs != null) && (qs.isCompleted())) ? "blabla.htm" : "blablalba.htm";
Edited by Snehulak
Link to comment
Share on other sites

  • 1 month later...
  • 1 month later...

Very nice guide, thanks! Im learning with Java and practise like this cannot be better i think :P

I had copy paste the quest Hatlings Big Adventure and created new NPC,s and questitems. I wanted to create a custom quest but this time for Strider > Wyvern. Can i extend Quest for this or do i have to unpack my l2jserver.jar and place the class files in there first?
Also do i have to edit any .bat files like when i add any item?

 

Thanks :)

Link to comment
Share on other sites

Hello, (almost) no matter the pack, quests are localized into datapack, meaning you can add a quest without having to recompile l2jserver. You only have to add a line into scripts.cfg (data/) or MasterHandler (data/scripts/handlers/MasterHandler.java) depending about the version of your pack. And, obviously, your quest.

 

Regarding .bat and items, I don't know exactly what you do, but it's probably wrong. :p

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...