Author Topic: [GUIDE] All about quests (infos, aCis standards)  (Read 1722 times)

Offline Tryskell

  • The cute dwarf
  • Administrator
  • Core
  • *
  • Posts: 3.763
  • Awards You don't like me, but I got the power. Forever dwarf.
[GUIDE] All about quests (infos, aCis standards)
« on: November 05, 2011, 08:13:21 PM »
GENERIC THINGS

TO KNOW

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:

Code: [Select]
	public Q013_ParcelDelivery()
{
super(13, "Parcel Delivery");

setItemsIds(PACKAGE);

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

In that "method" you can see recurrent stuff :
Code: [Select]
super(13, "Parcel Delivery");
defines the quest number and name used by the quest. Quest number is used by client to handle quest logs correctly, while the name is used by NPCs when showing multiple quests.

Code: [Select]
setItemsIds(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.

Code: [Select]
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)



"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."[/url]
  • 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

FORMATTING RULES

HTMs rules / L2OFF HTMs

If you see "Paagrio" instead of "Pa'agrio" in your HTMs, you probably use C4 HTMs. Consider to use L2OFF GF (compare quest progression first).

You can use L2OFF HTMs directly if you change the coding from UNICODE to ANSI. Don't forget to change HTMs bypasses, ofc.

Ty Tommy for the trick.

dropQuestItems / dropAlwaysQuestItems

When a onKill structure looks like this (and only like this) :
Code: [Select]
		if (st.getInt("cond") == 1 && st.getRandom(10) < 4)
{
st.giveItems(ORCISH_ARROWHEAD, 1);
if (st.getQuestItemsCount(ORCISH_ARROWHEAD) == 10)
{
st.set("cond", "2");
st.playSound("ItemSound.quest_middle");
}
else
st.playSound("ItemSound.quest_itemget");
}

You can (and should) use this simplified version :
Code: [Select]
		if (st.getInt("cond") == 1 && st.dropQuestItems(ORCISH_ARROWHEAD, 1, 10, 400000, true))
st.set("cond", "2");

dropQuestItems( parameters are following :
  • int : itemId
  • int : number of item to drop (min/max)
  • int : maximum of quests items
  • int : drop rate (on a 1.000.000 base ! 40% = 400.000)
  • boolean : send or don't send sounds (itemget and middle)

Another variation of dropQuestItems( exists, where you can use min/max number of items to drop.

Finally, if the chance equals 100%, use directly dropAlwaysQuestItems.

It can't be applied to all cases, so don't begin to change all without checking.

giveItems()

It can happen, so if you got following structure, where :
  • all itemIds are following each other ;
  • the chance to get each item is equal ;

For example :

Code: [Select]
int n = Rnd.get(100);
if (n < 25)
st.giveItems(KENDNELLS_ORDER1, 1);
else if (n < 50)
st.giveItems(KENDNELLS_ORDER2, 1);
else if (n < 75)
st.giveItems(KENDNELLS_ORDER3, 1);
else
st.giveItems(KENDNELLS_ORDER4, 1);

can become :

Code: [Select]
st.giveItems(Rnd.get(1836, 1839), 1); // Kendell's orders 1 to 4.

hasQuestItems()

When you get following structure :
Code: [Select]
if (st.getQuestItemsCount(ID) == 1) OR if (st.getQuestItemsCount(ID) == 0)
and the exact number isn't necessary for the check, try to use :
Code: [Select]
if (st.hasQuestItems(ID)) OR if (!st.hasQuestItems(ID))

aCis standards

Some "rules" have been used and improved with time. It can't be yours, but it's mine. It notably means I will edit your shared quest without any pity to match my standards. Editing my way can take time, but at least all quests got a similar look.

All quests are currently being refreshed using those standards (I will update them slowly, as it's pretty long and boring), so please, when you share a quest, be sure you made as much as possible.

Some rules can be funny to read, and probably many of you got no clue I edited all quests to get a similar look / think it's kinda perfectionist. Whatever. I will live.

A method content should have following order (drop options following cases) :
Code: [Select]
htmltext
setState
cond
sound
take items (in alphabetical order)
give items (in alphabetical order)

The exception to above is when quest ends. Method content is as following :
Code: [Select]
htmltext
take items (in alphabetical order)
give items (in alphabetical order)
sound
exitQuest

Variable naming

Naming conventions are simple:
- static stuff (variable, int[], map) : ITEM_NAME
- internal stuff like a npc instance shared amongst the whole quest : _nameOfNpc

If your name got multiples articles, or possessive article, such as "Kiki's Letter" or "Ancient Ghost of Elmoreden", I invite you to name your variables KIKI_LETTER or ANCIENT_GHOST. Avoid abreviations, such as KIKI_L or GHOST_EL, which are hard to understand.

If you got numerous items called the same, seperate them as ITEM_NAME_1, ITEM_NAME_2, etc.
« Last Edit: September 11, 2015, 06:07:26 PM by Tryskell »
Code: [Select]
<html><body>Triskel:<br>
Triskel does not speak with foolish fellows who do not know their profession!
</body></html>

Offline Tryskell

  • The cute dwarf
  • Administrator
  • Core
  • *
  • Posts: 3.763
  • Awards You don't like me, but I got the power. Forever dwarf.
Re: [TUTORIAL] Understand shit about quests
« Reply #1 on: September 11, 2015, 06:04:37 PM »
Updated this tutorial to follow latest aCis standards. Merged the 2 topics talking about quests.

Hasha is too :srsly:
Code: [Select]
<html><body>Triskel:<br>
Triskel does not speak with foolish fellows who do not know their profession!
</body></html>