Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста: - k7 R/ P. Y/ E' s* F5 n5 H6 n1 A4 _3 P. u
if getCount(st) >= 4 : " d6 r3 Q5 M" Y- Y+ |' L
completed(st)) u2 `7 m0 r! A; w( B# a
return$ u3 @; [" C( _4 N: t5 D
0 U w9 c1 t; u% u6 G
class Quest (JQuest):+ J" D# w1 p! Z$ f+ y+ W) ] Z
def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)3 W4 P; ]! X2 h
def onEvent (self,event,st):+ k X/ d! w. B: [& E2 \2 E
id = st.getState() 2 ]. e' r) ^4 B+ h. z/ Y
if id == CREATED : st.setState(STARTED)5 l/ K) V* W# ?
elif id == COMPLETED: pass: N* j# Q( S" V9 T
elif id == STARTED : check(st) 1 T7 [% |4 a* Q4 P! Q
return 6 b$ M) t" P% v5 Y& [
* D1 W+ B$ d5 n1 a5 {# l- N& h% p: L& i
QUEST = Quest(201,"Tutorial", "Tutorial quest")9 P, F$ G$ e b
CREATED = State('Start', QUEST) + k1 C. y4 @' N! v, ^4 h& E
STARTED = State('Started', QUEST) ! b' q9 a5 @, G; M; p
COMPLETED = State('Completed', QUEST)+ `% L+ y7 K5 Z
: v2 k* T# B5 f2 I" b
QUEST.setInitialState(CREATED) 5 k4 p! p- l- f/ u; r
Теперь рассмотрим, как это работает.* X6 B6 a" e- m; T! D7 l
Игрок подходит к начальному NCP (в данном случае 7056), нажимает на «Quest». Квест будет создан и состояние квеста перейдет к CREATED и игроку будет показана страничка Start.htm с описанием квеста. Тогда метод onEvent, поле открытия странички Start.htm переведет состояние квеста в STARTED и игроку будет показана страничка Started.htm, где будет опсание того, как найти keltirs и .т.д. 8 K! _3 ~" R+ K' D& v: T( S+ `$ N& J9 b+ l/ Y3 F% n
) }9 t5 Y6 S" ~- f, Y
При состоянии STARTED будет зарегистрирован дроп «fangs» при убийстве keltirs. Игрок может вернуться к стартовому NCP и спросить о квесте – метод onEvent будет вызван снова. Если у игрока не хватает необходимого количества предметов, то метод check() не переведет квест в следующее состояние и Started.htm будет показана снова. Но если игрок собрал необходимее количество предметов (в данном случае 4 клыка), то метод check() вызовет метод completed() который переведет квест в новое состояние COMPLETED, заберет все клыки, даст карту мира, т.к. это награда за квест, покажет Completed.htm и завершит квест.% t |% a0 i9 G, Z( K/ l4 g: O% m( W
# ^( T' y7 ?" `0 ^& v4 W6 B
) r( m' h: e1 I' A! q# V
Теперь давайте сделаем наш квест более похожим на то, что он должен из себя представлять. + V7 q4 L! ] j" wПрежде всего у нас есть 3 метода для объявления их в Яве – onTalk, onKill и onEvent. Если методы onTalk и onKill не объявлены, то за них все будет делать метод onEvent, т.е. определять квестовых монстров и вызывать диалоги NCP. Есть примечание, методы onTalk и onKill будут вызывать только диалоги с NCP в зависимости от текущего состояния квеста. Метод onKill будет вызываться только тогда, когда мы убиваем квестового монстра.; _6 w9 K7 L) ]9 {
+ q4 R' }% z1 o# i0 ` ( ^/ L" W# H l+ K* wДавайте рассмотрим как вызывается метод onKill при убийстве keltir в состоянии квеста STARTED: . h1 ~- W$ o. I+ v6 f; W
STARTED.addKillId(KELTIR_NPC_ID)
Скопировать код
и метод onKill в классе Quest: $ O T# H$ n7 l% n1 x- w- X3 h8 x
return "Collected "+str(n)+" of 4 fangs" 4 o/ G: e: y3 t
return
Скопировать код
Метод onKill (а так же метод onTalk) имеет следующие параметры:( o3 X3 t6 R. w8 G
2 R4 h+ V ?8 p) D. y6 l. A2 `! O3 u0 ?' m5 V1 \
• self – квест . L& D+ ]0 J: P# c+ `• npcId – ID NCP, которого мы должны убивать (если это метод onTalk, то ID того NCP, с которым мы должны поговорить)./ v5 {6 q0 n2 f2 _+ z/ n/ ?
• st – текущее состояние игрока.4 s8 }$ b9 i3 D6 v, [
; s3 r) `' s# D& k/ Y# g! L : I; g { g. `: NВ этом методе мы проверяем и отмечаем, является ли убитый NCP keltir’ом. В основном эта проверка не нужна, т.к. у нас только KELTIR_NPC_ID. - l/ V; h/ M q" U: L8 `$ `2 {' q& {) B0 T3 |; i0 O
" F* K: { h! x* ~% kЗатем проверяем количество предметов (в данном случае количество клыков), и если их вообще нет, то возвращаем строку "Chat0.htm", если только один предмет, то возвращаем строку "Chat1.htm", если же предметов 4 или больше, то "Chat4.htm". Если строка возвращена из методов onEvent, onKill или onTalk, то сервер покажет соответствующие htm. В Chat0.htm может иметь следующий текст: «Вы не имеете ни одного клыка, возвращайтесь позже, когда соберете 4 штуки и бла, бла, бла…», в Chat1.htm может быть следующий текст: «У Вас всего 1 клык, по этому соберите еще…». В Chat4.htm – «Вы собрали необходимое количество предметов, возвращайтесь к вашему тренеру, что бы завершить квест…»& }; m- O1 X6 Q. B- o# b5 P
* l8 A- `3 G6 m/ I
( ^" ?' B( P7 E7 n4 C% AПримечание: если в строка return начинается с "<html>", то будет показана страничка html с текстом, который стоит далее. Так вместо: ) q& v$ e# Y, d5 p8 Oreturn "Chat4.htm" 1 s* M# E9 F1 @- {0 d* b( f, Y$ n2 C / X( n; M3 J7 M& D/ s% p8 e1 d* k, w8 V( u( ~9 L4 T1 b5 H1 n- h
можно поставить:: B/ i- a" ], p5 `' ?9 n5 N
return "<html><body>Return to your trainer to complete the quest</body></html>"
Скопировать код
Так же если строка заканчивается без .htm или в начале нет <html>, то текст будет выведен, как системное сообщение в окне чата. В нашем случае мы сделаем так, что бы при каждом убийстве keltik выводилось системное сообщение: «Собрано N из 4-х клыков». : R, ]: |4 t+ i7 S) e* A F+ K. \9 `/ g/ B8 w3 t+ v/ ?
8 ?+ T' e( ]# A: w8 ]0 Y0 r
Наш код для onKill имеет один недостаток. Он будет постоянно показывать Chat0.htm, Chat1.htm и Chat4.htm, нам же необходимо, что бы Chat0.htm и Chat1.htm показывались только один раз. Как нам это сделать? С помощью переменных.! P I& C; c$ j' I* B$ h
/ T0 ?0 Q) `* ? O
6 h! R5 l: ]5 G0 [( c+ N
В каждом квесте строки могут храниться с помощью переменных. Эти переменные сохраняются в Вашей БД. В каждом методе мы можем назначить, прочитать и удалить переменные. Давайте изменим метод onKill, так что бы каждый диалог вызывался только один раз.& K. C4 c4 e' R0 [! a& l5 ]; B# N# l
if npcId == KELTIR_NPC_ID:* n" _ Z5 A7 u8 d6 Q4 U1 U
n = getCount(st) ! N( N5 I9 Q+ ?# e, f
if n == 0: # y- w' y! I0 M* A
if st.get('chat0') == None : 2 w; {! |- t7 x+ Q) U K
st.set("chat0", "true")# \# \* W: w' l* `8 g
return "Chat0.htm" 0 }: p8 |) _$ J9 D9 R8 U
elif n == 1:( H7 ^! x& k1 |& V
if st.get('chat1') == None :, q( w& n$ k! X* `& W
st.set("chat1", "true")9 |6 ^6 A/ B# R' C
return "Chat1.htm" : |0 Z! a( P) P& R$ {1 X/ Z- ]
elif n >= 4:# O* H; I s4 f' h
return "Chat4.htm", O3 \9 [5 y9 S: |3 M' e
return "Collected "+str(n)+" of 4 fangs" 5 |- P, \7 R0 [' @' i1 N
return
Скопировать код
Если у игрока нет клыков (n=0), то мы получаем занчение переменной 'chat0'. Когда метод onKill вызван в первый раз, то пока ни каких переменных не имеется и python возвращает значение None. В этом случае объявляется переменная и показывается диалог Chat0.htm. Когда мы убиваем keltir, но не получаем с него клык, функция st.get('chat0') возвращает строку true, а не None. И во второй раз окно с Chat0.htm не появится, но в окне чата появится строчка «Collected 0 of 4 fangs». По тому же принципу сделано и с Chat1.htm.2 L6 o! s5 G r8 e2 `: C# m9 Y* n
+ z6 V' ]+ T5 h6 h0 s( U3 P& S2 R" X( k: |
Вот конечный рабочий вариант квеста:& K7 _; m! ]1 X# v% E* Z* E# s
import sys . }# Y- [$ p+ `3 \# X' Y% M4 C
from net.sf.l2j.gameserver.model.quest import State# O* m3 C7 C8 W, j2 ~2 W0 o7 i$ K
from net.sf.l2j.gameserver.model.quest import QuestState * p6 H8 e7 V& O+ u x! v
from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest $ b6 `% F- V4 e; i$ q7 A- K" V: s
6 Z% z2 p+ ]# v+ K
KELTIR_NPC_ID = 12082; ` b% z' [" a# r- c0 l
FANGS_ITEM_ID = 1859 6 d, L! a9 z# I6 F
DROP_RATE = 500000 8 F) D' t" U2 S( }$ z X9 r& f
0 o5 ]7 `3 A' T* N
WORLD_MAP_ITEM_ID = 1665( Z6 v! Z) `/ K3 D& G
# ?- Z" d+ r$ \& W
def getCount(st) : ' s- n _6 z. M
return st.getQuestItemsCount(FANGS_ITEM_ID)" d6 J" B) H" ?