Зарегистрируйтесь сейчас чтобы найти еще больше друзей, и получить полноценный доступ ко всем функциям сайта!
Для просмотра Вам необходимо авторизоваться Если Вы еще не зарегистрированы, перейдите по ссылке:Зарегистрироваться
x
Хроники Interlude" M! x/ T/ d! Y; h1 [' ^4 C1 a
Сборка L2j
8 G! C( `' t, o" r5 jОбратите внимание: в файле htm стартового NCP обязательно должна быть ссылка на квест:
t/ P3 D3 G" C2 z3 L& m8 I+ m& f- STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста:
. E$ U% K; F4 q/ y/ F# I% y. X0 v) L, W/ Z: L. J) e
- if getCount(st) >= 4 :
& D- S9 @- ~6 ~& w% Z - completed(st): y3 m' [6 m+ D0 P0 Q' ]
- return
& r! h' {8 ^2 E5 D! s8 { - 5 j! m3 O" }8 r2 X2 _3 {4 z4 X
- class Quest (JQuest):
N: B/ b" F- u5 J1 D2 T - def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)+ b- C$ |0 q5 }2 G! C; ]# k' Y$ S
- def onEvent (self,event,st):
% P( S1 N7 l/ y1 ^6 R r - id = st.getState()
! J1 ~. g- A9 ~* v - if id == CREATED : st.setState(STARTED)( x% {" a& w2 V/ n
- elif id == COMPLETED: pass9 z6 z7 _: |* {1 e: x- m" }
- elif id == STARTED : check(st); l: L! y$ m ]) x' Q
- return d, c5 z& j2 `" K' C3 F
y+ f& G( [& b- QUEST = Quest(201,"Tutorial", "Tutorial quest")
; I! H1 C( M( J5 `" c( H* A - CREATED = State('Start', QUEST)7 H% o5 p% { k6 v- {
- STARTED = State('Started', QUEST)
1 x2 j. g* _# K5 I# u( H2 X* w - COMPLETED = State('Completed', QUEST)! q; |: U* a) E$ o T- n* d
) [4 K5 w* Y( t ?- B0 }4 X- QUEST.setInitialState(CREATED)4 l5 i/ b4 O9 M7 l4 I3 @
- QUEST.addStartNpc(7056)
6 X: ~6 o ?4 C |( q+ T$ Z/ ~2 h0 o/ z - STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код Теперь рассмотрим, как это работает.
% M, r& h; j3 d8 e; v$ k1 PИгрок подходит к начальному NCP (в данном случае 7056), нажимает на «Quest». Квест будет создан и состояние квеста перейдет к CREATED и игроку будет показана страничка Start.htm с описанием квеста. Тогда метод onEvent, поле открытия странички Start.htm переведет состояние квеста в STARTED и игроку будет показана страничка Started.htm, где будет опсание того, как найти keltirs и .т.д." F0 O) I% [, ^) Y8 O) E
' B; a+ W3 H$ }7 D E) i' U/ Q! w; R# }5 W0 f
При состоянии STARTED будет зарегистрирован дроп «fangs» при убийстве keltirs. Игрок может вернуться к стартовому NCP и спросить о квесте – метод onEvent будет вызван снова. Если у игрока не хватает необходимого количества предметов, то метод check() не переведет квест в следующее состояние и Started.htm будет показана снова. Но если игрок собрал необходимее количество предметов (в данном случае 4 клыка), то метод check() вызовет метод completed() который переведет квест в новое состояние COMPLETED, заберет все клыки, даст карту мира, т.к. это награда за квест, покажет Completed.htm и завершит квест.
: e/ w; V3 A1 E' t& ]& h' b f: S3 a& {3 }1 y: [4 F
0 r C, `8 i7 ^* w" m2 H
Теперь давайте сделаем наш квест более похожим на то, что он должен из себя представлять.
+ s* R2 \, b% I( G- W4 B/ W0 ZПрежде всего у нас есть 3 метода для объявления их в Яве – onTalk, onKill и onEvent. Если методы onTalk и onKill не объявлены, то за них все будет делать метод onEvent, т.е. определять квестовых монстров и вызывать диалоги NCP. Есть примечание, методы onTalk и onKill будут вызывать только диалоги с NCP в зависимости от текущего состояния квеста. Метод onKill будет вызываться только тогда, когда мы убиваем квестового монстра.' M% H6 s# Q; g4 O0 ^
0 O, n: @) V- V" K/ J" Q
! [) n4 G+ x% C; [/ nДавайте рассмотрим как вызывается метод onKill при убийстве keltir в состоянии квеста STARTED:* J9 n! B- J4 y3 e
- STARTED.addKillId(KELTIR_NPC_ID)
Скопировать код и метод onKill в классе Quest:: H8 |4 D9 B( C" P, W6 i
% n' [) Y% Y- L; \ y9 D- class Quest (JQuest):5 J; a' }8 N8 k, L
- ...$ M/ f* X/ c1 o K6 r
- def onKill (self,npcId,st):8 }* J! ]1 \1 U+ D
- if npcId == KELTIR_NPC_ID:
- E7 `, x* X' ~6 | - n = getCount(st)
: f( W7 X" S3 v5 S; Q - if n == 0:9 ^# @0 v3 Q$ l: K+ z/ C) S2 @- ~& I
- return "Chat0.htm"7 P, i5 @ g2 G2 t% Q& S
- elif n == 1:
* e: O5 c- O7 G6 U - return "Chat1.htm"
9 q8 H/ O& a6 Y. v+ c - elif n >= 4:
6 O5 j/ X( R0 c) h - return "Chat4.htm"
5 f. Y$ z9 z s6 e - return "Collected "+str(n)+" of 4 fangs"- e, T5 A7 A6 Z; Z. j, f$ ~! Z9 ^0 N
- return
Скопировать код Метод onKill (а так же метод onTalk) имеет следующие параметры:
2 g2 \% F/ H1 R! Y( j$ r7 `1 E
# V n0 F5 c( q( Y4 g' } C; z/ M& r% ^' T; Q
• self – квест
* M9 \$ q+ Y0 x* d0 ?, ^• npcId – ID NCP, которого мы должны убивать (если это метод onTalk, то ID того NCP, с которым мы должны поговорить).
5 a9 \. I& c a7 ]7 J• st – текущее состояние игрока." M3 }, }1 k! d+ \5 x
$ O! ^- p) U6 \0 ~! P
- t" q8 w' y! KВ этом методе мы проверяем и отмечаем, является ли убитый NCP keltir’ом. В основном эта проверка не нужна, т.к. у нас только KELTIR_NPC_ID.+ C6 [2 z9 f2 a0 u
9 T: r3 ?1 H2 U$ J
* ^! _! P* @) W- J0 |3 p# uЗатем проверяем количество предметов (в данном случае количество клыков), и если их вообще нет, то возвращаем строку "Chat0.htm", если только один предмет, то возвращаем строку "Chat1.htm", если же предметов 4 или больше, то "Chat4.htm". Если строка возвращена из методов onEvent, onKill или onTalk, то сервер покажет соответствующие htm. В Chat0.htm может иметь следующий текст: «Вы не имеете ни одного клыка, возвращайтесь позже, когда соберете 4 штуки и бла, бла, бла…», в Chat1.htm может быть следующий текст: «У Вас всего 1 клык, по этому соберите еще…». В Chat4.htm – «Вы собрали необходимое количество предметов, возвращайтесь к вашему тренеру, что бы завершить квест…»
6 A! f3 ~1 p O7 b) s; U$ n8 h% I) G8 @9 Q
3 n8 K ^9 u! Q/ i
Примечание: если в строка return начинается с "<html>", то будет показана страничка html с текстом, который стоит далее. Так вместо:& G+ e* [8 s" k* q4 n* V2 l# Q. v/ H
return "Chat4.htm"
0 j* O# T! g& [& G$ \+ s3 K5 z1 s6 w& M
6 j$ L8 y/ {& f2 B
можно поставить:
$ k6 Q4 C! d4 S' R0 S) F0 y- return "<html><body>Return to your trainer to complete the quest</body></html>"
Скопировать код Так же если строка заканчивается без .htm или в начале нет <html>, то текст будет выведен, как системное сообщение в окне чата. В нашем случае мы сделаем так, что бы при каждом убийстве keltik выводилось системное сообщение: «Собрано N из 4-х клыков».. n( @5 ^2 P9 e0 T& n
- M& T& |4 N0 R2 c$ g
8 ]! C7 N: _) D" P5 X8 D: SНаш код для onKill имеет один недостаток. Он будет постоянно показывать Chat0.htm, Chat1.htm и Chat4.htm, нам же необходимо, что бы Chat0.htm и Chat1.htm показывались только один раз. Как нам это сделать? С помощью переменных.9 ]. h- w# o) |" T3 f( \
2 [' \, _# i7 K; Z
8 L) _: _2 ~$ mВ каждом квесте строки могут храниться с помощью переменных. Эти переменные сохраняются в Вашей БД. В каждом методе мы можем назначить, прочитать и удалить переменные. Давайте изменим метод onKill, так что бы каждый диалог вызывался только один раз.5 U! D; ~0 F/ B( ^) O) H# }
- def onKill (self,npcId,st):
8 Z: o5 n; v: V9 d+ H - if npcId == KELTIR_NPC_ID:- f- q- C! @+ b7 e$ m! n
- n = getCount(st)( w2 D( f/ K1 T& E$ b2 B9 [
- if n == 0:( L" j ]/ m4 |' r
- if st.get('chat0') == None :3 D; Q: t2 P& a7 a* e+ j* J( Z
- st.set("chat0", "true")
' F% G' v- r3 a5 o" b* |3 ]7 w - return "Chat0.htm": h& c" s3 Q$ n
- elif n == 1:% o( w7 Y" M, Q1 [# ^9 L/ A
- if st.get('chat1') == None :
% {: _/ Z1 A: s; j ~1 ? - st.set("chat1", "true"). ~; k6 |+ E/ F j4 j! x" p2 N
- return "Chat1.htm"
' {9 Q" i) B6 w0 n7 }+ W# K - elif n >= 4:
6 A! P2 R( E* a' j* w; z - return "Chat4.htm"
4 Y3 Y# M2 [" t3 b- v - return "Collected "+str(n)+" of 4 fangs"
# o' V( n% x i! f" l - 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$ Y/ ~# v( }
# v; S/ B2 @ T* C# ^; p$ n, J, K( x1 n5 ]- t
Вот конечный рабочий вариант квеста:# J3 c4 q/ }; _* n6 I+ W5 C
- import sys
; E" ^1 K' R ~, z$ q* N6 m - from net.sf.l2j.gameserver.model.quest import State
9 q* R ~* A4 X4 g. z! t6 \9 m' u - from net.sf.l2j.gameserver.model.quest import QuestState/ R2 F( D8 Y. z0 j0 D0 a
- from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest
3 o0 R# F Q. }# C
: W# g$ }- k( z8 k' ~- KELTIR_NPC_ID = 12082+ F! H, X& B( ~7 N/ P
- FANGS_ITEM_ID = 1859
7 [% X! Q( t1 w1 O, B8 q- A0 Q) ] - DROP_RATE = 500000
# K$ q+ ?* T+ `8 K( C - Z' d& i" Q# p! H& i, D
- WORLD_MAP_ITEM_ID = 1665
0 y5 E* M& B3 |8 g. v3 t - # [" F4 b) \, k0 B5 v. ^" p
- def getCount(st) :
7 Q; [7 L% ]4 T+ }1 [( J/ u$ u; F - return st.getQuestItemsCount(FANGS_ITEM_ID)
9 N: t( n0 X' ?/ \+ B - ' [0 d% m2 I# b" C6 U
- def completed(st) :
, O5 ~& p; N% |( g! x - st.setState(COMPLETED)& G! m! K$ U( `, }5 \" K
- st.clearQuestDrops()4 n! X1 r1 a5 A$ R9 j/ ^
- st.takeItems(FANGS_ITEM_ID,-1) Q+ `# w+ J3 M7 [6 p; M9 X
- st.giveItems(WORLD_MAP_ITEM_ID,1)6 o2 n) z! q. M! {& V5 o! M
- st.exitQuest(False)
4 g [+ z0 h' t# F, R4 p$ M/ @; E - return d% I& Z* G& ?3 K0 h
$ ~- c" N4 V( w; c- def check(st) :
9 [* a- y% Y1 v. L& K9 X - if getCount(st) >= 4 :
; y5 o4 d+ I8 T2 o& [ - completed(st)
" M, n! F3 a' C# _+ s) G) | - return
/ s! R# N* s; h) d0 u4 V6 `: V
7 x3 y) |6 ^% y& I- class Quest (JQuest):
4 i- x7 Q; Z5 n7 @ - ) g2 q2 @' _% ~+ ^3 L' v
- def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)
' R8 ~" q2 y) {" V
z& Q# ^$ t) \2 X' M- def onEvent (self,event,st):
# P- d& o% j9 Z3 y! x - id = st.getState()! C7 C; j/ `- H' ]0 b! Q
- if id == CREATED : st.setState(STARTED)
" i; P0 B4 W! x. E2 P2 J+ R/ U - elif id == COMPLETED: pass2 U5 x( @( {; g4 U; g" h$ l" U: y! v
- elif id == STARTED : check(st)
! a. L: j) k$ y; G7 L - return% i+ L$ |4 z4 J2 f
( H; K5 p" z6 c8 x. q) h- def onKill (self,npcId,st):
* W7 f: L8 D7 n8 p# u - if npcId == KELTIR_NPC_ID:
9 |9 E) U3 W4 L) ]! [. G1 b/ Y) \! _ - n = getCount(st). r+ [/ s( z8 {/ }# K* x
- if n == 0:
& C, ]' w6 }0 S: ]) ?7 N - if st.get('chat0') == None :
0 O) y/ Z) ]) n& w: y - st.set("chat0", "true")
3 R7 R: ?7 `" b d - return "Chat0.htm"% [. i3 [ J8 u( p
- elif n == 1:
4 E q3 V6 k$ f \' T7 n( X - if st.get('chat1') == None :
: D7 f$ n4 J b8 V, y3 e- e - st.set("chat1", "true")
4 k" J& T. }0 |! f - return "Chat1.htm"$ Y) u, a0 j- L. F( h$ m* K
- elif n >= 4:
4 |! K; u8 k6 O - return "Chat4.htm"4 Z1 m, W: v& L$ Q1 O( k/ q. q
- return "Collect "+str(n)+" of 4 fangs", j# ?# ^+ n' N9 Y- i
- return
$ v( F5 F" o! N - 7 ?$ X3 u3 ~3 x
- QUEST = Quest(201, "Tutorial", "Tutorial quest")! R) b; Q3 v" m% X& g7 |2 b4 s1 h
- CREATED = State('Start', QUEST)
. @+ ^" q+ Y) e2 Y" z- a: M; R4 m/ R - STARTED = State('Started', QUEST)9 c( z: t$ F6 g; I4 u) G% ^
- COMPLETED = State('Completed', QUEST). L3 S3 p+ M. h7 h! \
0 {& a0 Z8 E( ]- QUEST.setInitialState(CREATED)
' U8 s+ k$ A# `) f - QUEST.addStartNpc(7056)8 K& p- J2 \7 ]
- QUEST.addStartNpc(7012)
- v+ L% `6 G7 B - QUEST.addStartNpc(7009)
+ S ?; O, S! |. B( L - QUEST.addStartNpc(7011)) ^5 j0 y9 G! [* F6 ~
- + ^0 j* ?6 X5 t+ T/ L) S1 D
- STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)( ]- t& g8 E+ u6 _4 e9 ]& S
- STARTED.addKillId(KELTIR_NPC_ID). ?* j. n O9 d+ C9 {# k! P, b+ `- R
- STARTED.addTalkId(7056)+ e' l+ ?3 u x' p+ X4 S
- STARTED.addTalkI d(7012)+ {1 j3 y1 P, p6 E- }# D" J
- STARTED.addTalkId(7009): }) s+ R( B/ X# g2 i- |
- STARTED.addTalkId(7011)
Скопировать код # } V4 S0 Z8 I S. q* ^4 k. X
- t- B9 A8 H6 V% M d& S
|