Зарегистрируйтесь сейчас чтобы найти еще больше друзей, и получить полноценный доступ ко всем функциям сайта!
Для просмотра Вам необходимо авторизоваться Если Вы еще не зарегистрированы, перейдите по ссылке:Зарегистрироваться
x
Хроники Interlude) u# V @) F2 U
Сборка L2j. F0 _ [" k0 A
Обратите внимание: в файле htm стартового NCP обязательно должна быть ссылка на квест:. j' h" S- f) L: H" P* b
- STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста:
/ s P _: V( `( e* Q: m
% M5 ^0 Z' w2 s! T0 R6 ?$ y: N- if getCount(st) >= 4 :+ y, c) t. e+ P8 A
- completed(st)) H; _4 d/ X7 [8 S6 P
- return
0 @! S) |5 E6 ^; @. u$ b' _) e
! q) ^3 S! U- t% A/ Y- class Quest (JQuest):
6 S6 f0 n! s' N# {9 { _ - def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)* e7 r" t/ r7 z, g( ]7 d
- def onEvent (self,event,st):3 T. X( T Q" m0 h$ B4 s, s7 o
- id = st.getState()
1 z- c; _6 z V" k, N! Q - if id == CREATED : st.setState(STARTED)
3 ^4 o4 \/ E; R+ A - elif id == COMPLETED: pass
& Q! z' l% R }+ j - elif id == STARTED : check(st)
# x5 v% r0 r( S, [ - return5 \' j% o; d% k
. n% n( c" D" K! V' q+ m* k& T5 e- QUEST = Quest(201,"Tutorial", "Tutorial quest")) n7 ~# t& P# l. T+ R
- CREATED = State('Start', QUEST)& S7 O% W- c; L/ k1 n: Q4 y
- STARTED = State('Started', QUEST)% I$ x5 e0 X" H5 p2 @$ c2 w: x
- COMPLETED = State('Completed', QUEST)
$ }5 y6 @8 Z! E+ Y6 y6 a; S, U; T" G - 2 j* z* Q6 n# _& w: b# K9 a2 r
- QUEST.setInitialState(CREATED)& o7 ~0 x4 c* S. E/ i
- QUEST.addStartNpc(7056)
1 q1 ?' g: \# x( \" \& }. B+ Z, s& w - STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код Теперь рассмотрим, как это работает.3 ~, g7 E) M! f
Игрок подходит к начальному NCP (в данном случае 7056), нажимает на «Quest». Квест будет создан и состояние квеста перейдет к CREATED и игроку будет показана страничка Start.htm с описанием квеста. Тогда метод onEvent, поле открытия странички Start.htm переведет состояние квеста в STARTED и игроку будет показана страничка Started.htm, где будет опсание того, как найти keltirs и .т.д.3 p: v% R) b5 W) D* W
: l- Y d- Q8 z. A
, J- u8 a! i0 TПри состоянии STARTED будет зарегистрирован дроп «fangs» при убийстве keltirs. Игрок может вернуться к стартовому NCP и спросить о квесте – метод onEvent будет вызван снова. Если у игрока не хватает необходимого количества предметов, то метод check() не переведет квест в следующее состояние и Started.htm будет показана снова. Но если игрок собрал необходимее количество предметов (в данном случае 4 клыка), то метод check() вызовет метод completed() который переведет квест в новое состояние COMPLETED, заберет все клыки, даст карту мира, т.к. это награда за квест, покажет Completed.htm и завершит квест.0 H* L8 j* w1 s0 i5 R
, M- H- |8 ^8 y7 \+ W( c# d& a6 |* ?) D, d* \' b2 `+ S
Теперь давайте сделаем наш квест более похожим на то, что он должен из себя представлять.
\3 z* D% m# r9 \, c& [$ fПрежде всего у нас есть 3 метода для объявления их в Яве – onTalk, onKill и onEvent. Если методы onTalk и onKill не объявлены, то за них все будет делать метод onEvent, т.е. определять квестовых монстров и вызывать диалоги NCP. Есть примечание, методы onTalk и onKill будут вызывать только диалоги с NCP в зависимости от текущего состояния квеста. Метод onKill будет вызываться только тогда, когда мы убиваем квестового монстра.
* U; T" L- \# F" ~7 k& p$ q% w0 Q. T. y# c
. o8 S' K5 } z% P- u+ H- `. x9 t) GДавайте рассмотрим как вызывается метод onKill при убийстве keltir в состоянии квеста STARTED:! g/ G. M) U% B( g, R* e
- STARTED.addKillId(KELTIR_NPC_ID)
Скопировать код и метод onKill в классе Quest:
% [2 ~9 O% g+ Z x; J
$ n: }" j! j. I( }" B- class Quest (JQuest):- [! _0 ~9 p p% z
- ...
( m: f* C8 J' I5 \, E2 A) R7 Q - def onKill (self,npcId,st):) o0 E; ~2 L6 r( z, x2 d m0 h. G+ F8 H+ l
- if npcId == KELTIR_NPC_ID:( W h6 H/ f7 }9 M; e. A: F
- n = getCount(st)
/ l/ S9 y2 {! o; ~; Y# B8 p - if n == 0:) k& [: ^: i5 z2 }/ D! A9 R
- return "Chat0.htm") @: T; @; G1 h- W
- elif n == 1:* s Q0 b# F$ V; P
- return "Chat1.htm"
0 t( W! u$ I9 U8 ` - elif n >= 4:: ?& h) {( Q. E" r6 L
- return "Chat4.htm"
$ \' N: @% x/ h - return "Collected "+str(n)+" of 4 fangs"
' @/ Z5 x. y y9 W2 f1 \ - return
Скопировать код Метод onKill (а так же метод onTalk) имеет следующие параметры:0 o0 Q/ C6 D7 p
& O) Y* O1 g/ n. [
{; s* J1 |* l$ p* A% t0 q• self – квест) `- `9 N3 X' j1 i9 b
• npcId – ID NCP, которого мы должны убивать (если это метод onTalk, то ID того NCP, с которым мы должны поговорить).
* ?9 g8 P8 t4 G Q4 u% z9 E• st – текущее состояние игрока.
( |2 W/ L5 @; H4 s; R& n6 j/ j: z6 m+ b' c
$ q7 A6 X$ \- R' B( B* `' R
В этом методе мы проверяем и отмечаем, является ли убитый NCP keltir’ом. В основном эта проверка не нужна, т.к. у нас только KELTIR_NPC_ID.
& z# T) i% E# A. P; w. L7 b
- ]/ d( U4 d7 L$ G; D
7 P; s0 @" S/ F* }2 E6 yЗатем проверяем количество предметов (в данном случае количество клыков), и если их вообще нет, то возвращаем строку "Chat0.htm", если только один предмет, то возвращаем строку "Chat1.htm", если же предметов 4 или больше, то "Chat4.htm". Если строка возвращена из методов onEvent, onKill или onTalk, то сервер покажет соответствующие htm. В Chat0.htm может иметь следующий текст: «Вы не имеете ни одного клыка, возвращайтесь позже, когда соберете 4 штуки и бла, бла, бла…», в Chat1.htm может быть следующий текст: «У Вас всего 1 клык, по этому соберите еще…». В Chat4.htm – «Вы собрали необходимое количество предметов, возвращайтесь к вашему тренеру, что бы завершить квест…»
7 ?, E* Q) l7 @+ i/ t0 q
- o* J( I$ _" R; u! O0 ~8 ~* G6 g
2 t; N3 R* L* M' ]8 S' wПримечание: если в строка return начинается с "<html>", то будет показана страничка html с текстом, который стоит далее. Так вместо:
A6 f- t$ ]) ^) `return "Chat4.htm"5 R8 ]- G3 r$ b" g; W
4 W1 S! K* Z/ g& F' ?- G! t2 k# \0 ]8 p9 Y1 ~+ f, w9 [1 d
можно поставить:
* k3 D" M% q! u- o; ?4 R- return "<html><body>Return to your trainer to complete the quest</body></html>"
Скопировать код Так же если строка заканчивается без .htm или в начале нет <html>, то текст будет выведен, как системное сообщение в окне чата. В нашем случае мы сделаем так, что бы при каждом убийстве keltik выводилось системное сообщение: «Собрано N из 4-х клыков».2 v+ s) Z1 v3 C4 T8 Y' q
1 x* q# |' ?% }, E$ U- u& d
# M# A' O9 w6 K2 w5 F
Наш код для onKill имеет один недостаток. Он будет постоянно показывать Chat0.htm, Chat1.htm и Chat4.htm, нам же необходимо, что бы Chat0.htm и Chat1.htm показывались только один раз. Как нам это сделать? С помощью переменных.
+ E: d& n4 P2 X6 e* _' z4 o. d/ q+ `( x
, k; Q4 y, v% ?8 M' v# T$ }
" ~) j/ O& ]% G( f# jВ каждом квесте строки могут храниться с помощью переменных. Эти переменные сохраняются в Вашей БД. В каждом методе мы можем назначить, прочитать и удалить переменные. Давайте изменим метод onKill, так что бы каждый диалог вызывался только один раз.
6 [# P4 l: D1 O/ ^0 z- def onKill (self,npcId,st):2 g) j# i- C$ c& a6 S% d
- if npcId == KELTIR_NPC_ID:
+ `' B. S) P' s - n = getCount(st)7 Q2 f* @7 Q# I: H* w7 X6 a6 F
- if n == 0:
' v5 f: D% }' J; M - if st.get('chat0') == None :. m3 k4 p$ @* |+ M) S6 y. e) |
- st.set("chat0", "true")1 l' {# ~$ u. W( V" J
- return "Chat0.htm"( q) ?, Z( \9 ^7 j1 Q1 @
- elif n == 1:
7 K, @* A4 [/ ?- O - if st.get('chat1') == None :
; ?' n- c5 c9 l* M. T: l3 q5 g; v# l - st.set("chat1", "true")9 k$ C2 k p, V2 U/ h9 M0 ?
- return "Chat1.htm"
* j* F6 P+ o" } - elif n >= 4:
) ]* j/ ?# y' t$ h5 D - return "Chat4.htm") P5 n% {- D4 S8 m# t7 y- F& j
- return "Collected "+str(n)+" of 4 fangs"5 t0 R# s/ }& k [4 ~9 E! s
- return
Скопировать код Если у игрока нет клыков (n=0), то мы получаем занчение переменной 'chat0'. Когда метод onKill вызван в первый раз, то пока ни каких переменных не имеется и python возвращает значение None. В этом случае объявляется переменная и показывается диалог Chat0.htm. Когда мы убиваем keltir, но не получаем с него клык, функция st.get('chat0') возвращает строку true, а не None. И во второй раз окно с Chat0.htm не появится, но в окне чата появится строчка «Collected 0 of 4 fangs». По тому же принципу сделано и с Chat1.htm.
! S, }1 @7 V% L7 |( J0 ~) X! T) W' Z
/ d, c, |3 }# A, H) @
Вот конечный рабочий вариант квеста:6 S ]: P! i5 m W
- import sys
0 B' F& \: L# a# v - from net.sf.l2j.gameserver.model.quest import State
9 |% U8 m+ N0 b* U, d - from net.sf.l2j.gameserver.model.quest import QuestState1 {% z. W1 u* ~3 Z! Q- t T
- from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest
6 K8 K# g C% X: p - 2 p" K% m* c9 n' Q0 {' R
- KELTIR_NPC_ID = 12082
# S$ B2 g* e" Z7 E1 \; O - FANGS_ITEM_ID = 18598 y# ~4 p6 t& K% }% i) {
- DROP_RATE = 500000
) y; C& G; L& s. v& F; W
6 j" G: f& R' `! u3 z3 M0 B- WORLD_MAP_ITEM_ID = 1665
; E$ f0 {+ e# i: h+ ?6 ~9 ^
/ B2 N/ K$ i0 S! Q! O9 p8 `- def getCount(st) :
0 `" j# m3 X) o6 L4 t0 d - return st.getQuestItemsCount(FANGS_ITEM_ID)
' N! O& m2 i8 u - & V0 g. Z- `; h. `9 {( i
- def completed(st) :% M' P1 w+ | x' ?# t7 u: d
- st.setState(COMPLETED)
Q7 w' \0 ?6 a1 f+ m6 H - st.clearQuestDrops()
7 A# ]1 R* L- ^4 ^, j% J - st.takeItems(FANGS_ITEM_ID,-1)6 ?/ F) y2 Q9 j" w) Q9 |
- st.giveItems(WORLD_MAP_ITEM_ID,1)2 Z8 A% V) X0 O* v# G2 e5 _
- st.exitQuest(False)
+ p$ r: D6 h* E: X - return
/ y& j$ }! j8 `. [ - , B2 m& x# |4 U3 x0 _
- def check(st) :
( o% Y; G" y0 F - if getCount(st) >= 4 :
' o) z$ \1 Q! K& }1 e; w% a, J - completed(st)% a) y9 p* w7 B
- return4 X9 T; I. h5 d u$ y- h) \
- 9 H+ ?8 e. i& H
- class Quest (JQuest):' ^% u" ^. m9 G \0 ~
- 0 i1 @( O, \4 N& i6 ~$ o
- def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)
$ U8 |" E2 {& a
& s3 _; R v4 i. W( Y# i5 q- def onEvent (self,event,st):
% b8 [1 [% b& E6 V$ I - id = st.getState()5 q; y# a; Y4 S: w0 r! U' ^) c
- if id == CREATED : st.setState(STARTED)9 V# P' Y2 m8 f6 j7 k
- elif id == COMPLETED: pass. J! a. `- U4 [' p4 W2 ~
- elif id == STARTED : check(st)& ~& X0 J! ]* f8 B: G
- return) @& V1 Z, N( F- R
$ T5 ~7 i- v( k5 I7 D8 j% ^# w- def onKill (self,npcId,st):
/ s# y- |9 X, q8 b - if npcId == KELTIR_NPC_ID:3 L: r9 p+ r6 z1 G$ _
- n = getCount(st): A- v- h% q1 n' Z5 S" i2 k
- if n == 0:
9 _- f N& P: j# }* C8 B - if st.get('chat0') == None :
" M) F! ~/ @7 {; r5 } - st.set("chat0", "true")
, ^7 d" W2 q* C$ X; W4 m2 e: G - return "Chat0.htm"; g# \1 u- `1 L) D w: W) P
- elif n == 1:
9 l1 L/ R- x6 k1 {! H6 F3 j' z - if st.get('chat1') == None :
& j n; S" e1 W( v2 ?" ] - st.set("chat1", "true")
4 h! q3 k0 P- }- G. m$ q - return "Chat1.htm"
' M8 `. z0 J8 Q( e* l3 \. C - elif n >= 4:& N7 j" \& i4 X
- return "Chat4.htm"5 q* t+ L% N0 u0 z- a# \. f
- return "Collect "+str(n)+" of 4 fangs"
W7 R7 S: F7 P; c - return2 i3 N; [+ @8 q' O) e- y7 v% I
, N$ C7 Q$ `" B4 Q- QUEST = Quest(201, "Tutorial", "Tutorial quest"). }1 D! F+ w) s/ \+ R. `6 @) Q
- CREATED = State('Start', QUEST)
. n8 J+ z% |$ u$ k0 @* T+ n - STARTED = State('Started', QUEST)0 W9 j4 A; \9 U7 Y* ^ @
- COMPLETED = State('Completed', QUEST)
8 K" t3 g6 j1 ]$ b - # b y* m' I7 `# K& U. S
- QUEST.setInitialState(CREATED)# U1 }- o: d' d0 A5 }; _
- QUEST.addStartNpc(7056)8 B, I( k; Q8 |, ]' j: j Z' T. B
- QUEST.addStartNpc(7012)
4 i, Q& x: o3 y5 N4 a0 _ - QUEST.addStartNpc(7009)
2 i, m c; W R( s$ H - QUEST.addStartNpc(7011)
) o- v: f' k+ q( _7 O# J9 N; S
" Z$ H" I# d0 f* w2 a- STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)2 Y: R8 o: N- c- b/ T- Z0 W6 u
- STARTED.addKillId(KELTIR_NPC_ID)( H# y4 ~8 D1 O2 {, a- N
- STARTED.addTalkId(7056)9 n# T4 h/ W$ h1 u% S1 ? q, X# E v
- STARTED.addTalkI d(7012)- Z- \7 T% j& ~; |* G1 Q6 L
- STARTED.addTalkId(7009)5 R/ y% I' u7 y8 p: K; m
- STARTED.addTalkId(7011)
Скопировать код 6 u- Y# w( M) C7 u0 J
5 L* x y: `, {$ @ |