Зарегистрируйтесь сейчас чтобы найти еще больше друзей, и получить полноценный доступ ко всем функциям сайта!
Для просмотра Вам необходимо авторизоваться Если Вы еще не зарегистрированы, перейдите по ссылке:Зарегистрироваться
x
Хроники Interlude
9 d+ X4 ]6 Q% @: `$ mСборка L2j4 ]$ W6 o. _, m+ @
Обратите внимание: в файле htm стартового NCP обязательно должна быть ссылка на квест:
( ]7 o; A! I U" \- STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста:1 v" { k* O" I6 ]5 T+ X, ~
6 U7 s3 `) f) @# n; R- if getCount(st) >= 4 :, d* }# _. d- }$ Z; ], F; P( [. a
- completed(st)
' E/ B' |. @* _' V/ \( y - return
h/ j8 ^3 `* @* x2 }# P - 7 ?+ y; {$ S) v6 X1 I! g8 b2 a: A
- class Quest (JQuest):
! q" A# W& \1 E) p$ Y - def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)5 q% R) R: V! j( q! F# U+ K0 b
- def onEvent (self,event,st):, f2 U4 f4 O% W0 h4 ]% @- V: J8 K
- id = st.getState()" _7 H# O% J' L1 m& D% q
- if id == CREATED : st.setState(STARTED)7 z) x! v6 N; ]+ m
- elif id == COMPLETED: pass
' H# C* _* k! w2 m Y8 Q - elif id == STARTED : check(st)
0 l5 k+ t A) g8 y - return
! J, ~. E$ F) a6 n8 ? - 8 }& W, ~' C- c# a6 U! g
- QUEST = Quest(201,"Tutorial", "Tutorial quest")
, |* v/ U6 X2 x5 G - CREATED = State('Start', QUEST)
$ F D: ]2 S+ u8 Y0 S1 @) f - STARTED = State('Started', QUEST)+ q; ~1 G& q1 R
- COMPLETED = State('Completed', QUEST)$ Y1 j/ z. o9 ~9 X! e0 S4 _; p
- 7 L8 b4 @0 @9 m3 V0 D; A
- QUEST.setInitialState(CREATED)
; D5 N w0 q. H5 m - QUEST.addStartNpc(7056)
+ g( I( B: f" i1 {& g - STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код Теперь рассмотрим, как это работает.
0 Q0 O( {4 h) [3 F* P- R" B- L8 J8 wИгрок подходит к начальному NCP (в данном случае 7056), нажимает на «Quest». Квест будет создан и состояние квеста перейдет к CREATED и игроку будет показана страничка Start.htm с описанием квеста. Тогда метод onEvent, поле открытия странички Start.htm переведет состояние квеста в STARTED и игроку будет показана страничка Started.htm, где будет опсание того, как найти keltirs и .т.д.
5 o: m1 \2 d: B# S3 t
; [* V0 k9 o4 q8 s1 v6 h% l) y2 R b8 D. j. q) a; G
При состоянии STARTED будет зарегистрирован дроп «fangs» при убийстве keltirs. Игрок может вернуться к стартовому NCP и спросить о квесте – метод onEvent будет вызван снова. Если у игрока не хватает необходимого количества предметов, то метод check() не переведет квест в следующее состояние и Started.htm будет показана снова. Но если игрок собрал необходимее количество предметов (в данном случае 4 клыка), то метод check() вызовет метод completed() который переведет квест в новое состояние COMPLETED, заберет все клыки, даст карту мира, т.к. это награда за квест, покажет Completed.htm и завершит квест.
0 b: B5 Y9 {, Z) w- S- u5 D' K: w0 J8 D( ?& }
' b- V! \. J1 K3 \' i% @7 T
Теперь давайте сделаем наш квест более похожим на то, что он должен из себя представлять.
' C6 H, v% p l; ^3 ~Прежде всего у нас есть 3 метода для объявления их в Яве – onTalk, onKill и onEvent. Если методы onTalk и onKill не объявлены, то за них все будет делать метод onEvent, т.е. определять квестовых монстров и вызывать диалоги NCP. Есть примечание, методы onTalk и onKill будут вызывать только диалоги с NCP в зависимости от текущего состояния квеста. Метод onKill будет вызываться только тогда, когда мы убиваем квестового монстра.
8 R! U# B, D* p; P8 r8 n) A
1 Z( q5 t" L9 o3 P
# w6 R- |9 s# d: z8 RДавайте рассмотрим как вызывается метод onKill при убийстве keltir в состоянии квеста STARTED:
, I4 B+ r- H0 T o- STARTED.addKillId(KELTIR_NPC_ID)
Скопировать код и метод onKill в классе Quest:. S. o4 M5 l2 @- N
8 Z% p6 N ?4 r4 x
- class Quest (JQuest):
H1 e* X& w7 K - ...
1 z) N# c% H% T2 K( t3 l5 ]# i - def onKill (self,npcId,st):- X% f8 t. t/ [
- if npcId == KELTIR_NPC_ID:1 U8 o4 k# B1 w% E4 T3 x0 }5 {
- n = getCount(st)+ L% L7 I5 t! Z& b
- if n == 0:
, h3 ]. P; I; X' u0 F1 i - return "Chat0.htm") w: ^4 L5 E4 i' {$ ~
- elif n == 1:
' j3 [- a; L, D Q6 c' ^ - return "Chat1.htm"
: K+ U/ I+ A: g/ ], t - elif n >= 4:! ]( @" H# J( h5 k! n9 n, `# U
- return "Chat4.htm"
6 m3 t6 ~. c7 I% \3 o3 e - return "Collected "+str(n)+" of 4 fangs"; }2 Y! C8 H3 e! I! |
- return
Скопировать код Метод onKill (а так же метод onTalk) имеет следующие параметры:+ U1 M2 M/ Y z- X) o% \% @$ e
! p, j! V" P' x: T6 Y5 w' R+ C' }0 k3 N1 m1 T1 Z$ U
• self – квест
5 ^0 y' x) N2 o• npcId – ID NCP, которого мы должны убивать (если это метод onTalk, то ID того NCP, с которым мы должны поговорить).5 q% f; I- @ k* W9 T0 `
• st – текущее состояние игрока.
' {: S Y0 A: x- ]- u
; z; I' l1 O. J* n+ a+ D" U' ^- l% W( N% u
В этом методе мы проверяем и отмечаем, является ли убитый NCP keltir’ом. В основном эта проверка не нужна, т.к. у нас только KELTIR_NPC_ID.
( b0 P9 Q) l; {4 C' i4 n6 T% q$ K; p8 X% f" \ U; I( v
* O0 @+ \" q# q4 z/ PЗатем проверяем количество предметов (в данном случае количество клыков), и если их вообще нет, то возвращаем строку "Chat0.htm", если только один предмет, то возвращаем строку "Chat1.htm", если же предметов 4 или больше, то "Chat4.htm". Если строка возвращена из методов onEvent, onKill или onTalk, то сервер покажет соответствующие htm. В Chat0.htm может иметь следующий текст: «Вы не имеете ни одного клыка, возвращайтесь позже, когда соберете 4 штуки и бла, бла, бла…», в Chat1.htm может быть следующий текст: «У Вас всего 1 клык, по этому соберите еще…». В Chat4.htm – «Вы собрали необходимое количество предметов, возвращайтесь к вашему тренеру, что бы завершить квест…»% V/ [6 a/ i% w: w0 Y/ V
5 p$ k" N4 u# q+ S% T2 a( O
- X+ Z; F: E- z+ I G
Примечание: если в строка return начинается с "<html>", то будет показана страничка html с текстом, который стоит далее. Так вместо:- h T- t; N7 J/ O' w8 z# U6 ^
return "Chat4.htm"7 G3 }, Y8 j/ q: H
0 A. j6 k0 D+ y. U) m: H0 s5 x, @( ]% D6 P6 v$ F( P3 ?
можно поставить:
) P! X3 j X2 [1 a5 n1 l- return "<html><body>Return to your trainer to complete the quest</body></html>"
Скопировать код Так же если строка заканчивается без .htm или в начале нет <html>, то текст будет выведен, как системное сообщение в окне чата. В нашем случае мы сделаем так, что бы при каждом убийстве keltik выводилось системное сообщение: «Собрано N из 4-х клыков».2 w; q7 G/ B( z3 E* p
$ D0 m$ a% f9 n9 _% ]# t0 D
2 o: E! g: Z: I* b! lНаш код для onKill имеет один недостаток. Он будет постоянно показывать Chat0.htm, Chat1.htm и Chat4.htm, нам же необходимо, что бы Chat0.htm и Chat1.htm показывались только один раз. Как нам это сделать? С помощью переменных.
/ m) U% I" m; q( c+ j @
3 k$ m( \. u9 D C. C8 l2 y& m0 t9 V$ v
В каждом квесте строки могут храниться с помощью переменных. Эти переменные сохраняются в Вашей БД. В каждом методе мы можем назначить, прочитать и удалить переменные. Давайте изменим метод onKill, так что бы каждый диалог вызывался только один раз.( _2 i9 b9 n; B/ J1 A
- def onKill (self,npcId,st): `7 U/ s/ y9 x9 c0 r5 J
- if npcId == KELTIR_NPC_ID:+ j3 e# g: T& `0 [. h
- n = getCount(st)) b8 Q8 z6 L4 I2 _# T+ g
- if n == 0:
( u: y5 E+ f" b& T: q - if st.get('chat0') == None :% W i/ U% t, Z8 M- ]4 W$ G& Y2 U
- st.set("chat0", "true")3 b7 u* r5 C6 V6 G" _
- return "Chat0.htm"
. T" H4 H0 w( }( _6 p5 P: l - elif n == 1:
. J: Q/ v* ] ?2 W1 ~9 t% `, ` - if st.get('chat1') == None :
' g# q( M. C- v( X* q5 ? F+ w+ N - st.set("chat1", "true")
% B. s8 ^3 y6 y) N5 h- V - return "Chat1.htm"
( x! ^, F9 T7 B$ |" h- i. G) N - elif n >= 4:, u V! ?9 E9 b0 h7 n
- return "Chat4.htm"+ A# l. l, w, L( A
- return "Collected "+str(n)+" of 4 fangs"* {$ ~6 g: `$ m4 ? o O
- return
Скопировать код Если у игрока нет клыков (n=0), то мы получаем занчение переменной 'chat0'. Когда метод onKill вызван в первый раз, то пока ни каких переменных не имеется и python возвращает значение None. В этом случае объявляется переменная и показывается диалог Chat0.htm. Когда мы убиваем keltir, но не получаем с него клык, функция st.get('chat0') возвращает строку true, а не None. И во второй раз окно с Chat0.htm не появится, но в окне чата появится строчка «Collected 0 of 4 fangs». По тому же принципу сделано и с Chat1.htm.+ U/ l; _$ l& T ^8 i4 Q# c: T
9 t2 o/ Y4 g' K' f+ B' j1 K2 |* u9 y5 r+ ~ V
Вот конечный рабочий вариант квеста:; [; b2 M5 e9 a# C3 B- B2 F
- import sys0 a) O+ d$ u* x+ U4 |- I% f
- from net.sf.l2j.gameserver.model.quest import State
0 r9 _' {7 [0 ^7 F6 i! \- J - from net.sf.l2j.gameserver.model.quest import QuestState3 n* Q7 L& Y+ H- A' y# E
- from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest; H/ x; k r z. h: |- H
- ; k( u( d5 d$ F n, h8 F" Y
- KELTIR_NPC_ID = 12082
9 a3 i, z- t+ u% V6 V- ^) R+ V" i - FANGS_ITEM_ID = 1859( E8 A; _- N: v) v
- DROP_RATE = 500000 l$ Y* S, b) T0 E2 `% G m
- 6 q9 V0 V' B' b4 A" ~0 U! r6 N0 T
- WORLD_MAP_ITEM_ID = 1665
1 U9 Y* I6 g, P0 I8 r - * C0 S( O$ z4 m) b
- def getCount(st) :, b, r. J, g& X9 q& j+ y
- return st.getQuestItemsCount(FANGS_ITEM_ID)
" v- y& {8 i0 E - 3 g! y1 r! B1 Y5 x" S# s
- def completed(st) :
+ I3 k' g3 v, C/ j - st.setState(COMPLETED)
; U) R! T& R {$ [6 [ - st.clearQuestDrops()
% n) V; M& Z' E) Y) J e - st.takeItems(FANGS_ITEM_ID,-1)
8 A* Z& v T* r3 d: O- @+ d - st.giveItems(WORLD_MAP_ITEM_ID,1)
% H6 e' H' v7 s/ D, @" f# ^ - st.exitQuest(False); f3 R" }3 V* N# O6 i) o
- return
+ P: Y4 d3 ~( K) O
0 e; T7 b5 g0 M( X& g: z6 i( T& b- def check(st) :
3 [2 X. |6 A$ ]7 x# X# ] - if getCount(st) >= 4 :. \+ N% N! Q0 ^
- completed(st)
o" g0 k9 c& R - return
3 H3 |5 o6 x/ F! i. E8 q1 [
3 O3 [% k+ U) W$ d- class Quest (JQuest):
& n! j W( Z& r" u e1 U( B
3 M3 l' p {4 E- M1 B) y1 t, d6 S- def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)
7 l; v4 H" ~! T5 r/ a; p - . c, b/ P4 W0 o% r( z! i! R
- def onEvent (self,event,st):" T1 I' [7 T5 J" u& J( x
- id = st.getState()/ t9 P9 x" J5 O
- if id == CREATED : st.setState(STARTED)) Q1 ?- T. M+ g) g3 w
- elif id == COMPLETED: pass' O8 b* Y6 q% A# H! X9 t" {9 o
- elif id == STARTED : check(st)1 p2 P' k0 o2 l3 Q f, H K* N9 I: u
- return
! ~! s# b( m$ ?3 G; Z' F& C: G - + |5 h7 D2 @8 d5 ^3 p
- def onKill (self,npcId,st):% L8 X& w Z+ E1 M8 G
- if npcId == KELTIR_NPC_ID:
2 w, S" w/ E/ D1 z5 o, T - n = getCount(st)+ N; W. w0 u) E6 G; |
- if n == 0:1 j. P% B) z* s$ o; a) g) S! B" @
- if st.get('chat0') == None :1 Y0 L0 J) |4 \% }9 c/ B6 ?' ]' a
- st.set("chat0", "true")
# w4 y0 o* t1 u6 B- \$ d' O - return "Chat0.htm"
$ K& ~8 e4 H6 K* [ - elif n == 1:* h5 \$ R. F+ _$ w7 z2 c
- if st.get('chat1') == None :& C& ]. Q W0 h, l1 Q
- st.set("chat1", "true"): t$ L" D g* v+ y* Y: O: ?4 y
- return "Chat1.htm"
% v$ c# \. m2 q: i5 O4 V9 Z2 ~5 w - elif n >= 4:
, S- _5 }# j) T. v6 e8 o - return "Chat4.htm"
# s( @/ U2 M$ ~: F, H3 h - return "Collect "+str(n)+" of 4 fangs"
" M( [2 P- i# ~) q v; x" } - return; q7 r4 P5 G% m
! h v4 d- c& c g7 q/ H' [- QUEST = Quest(201, "Tutorial", "Tutorial quest")
* p3 e. N5 i5 {/ z$ m! p% ? - CREATED = State('Start', QUEST), r( ?( Y5 W1 d7 d
- STARTED = State('Started', QUEST)5 w/ g% y' H' {3 f& U
- COMPLETED = State('Completed', QUEST)
. z0 `- X! l5 G( ?
* t& D( B+ [+ E" ?+ S- QUEST.setInitialState(CREATED)/ L1 o2 T! Z& w* i
- QUEST.addStartNpc(7056)
0 @) n" C: Y# A$ n* E; j - QUEST.addStartNpc(7012)& f; A$ p+ k0 ^( F. Y
- QUEST.addStartNpc(7009)/ u) c. i% W5 E: H x8 J
- QUEST.addStartNpc(7011)" L9 R$ C& s3 v1 n' M+ n
% l. }! M4 Z& N$ V: g5 V/ P- STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)6 C- i, I' T, E# o( B
- STARTED.addKillId(KELTIR_NPC_ID)9 ]' K/ K1 B0 u8 V
- STARTED.addTalkId(7056)
% o2 c' t8 ]: \ - STARTED.addTalkI d(7012)
f* U+ {1 | D% C - STARTED.addTalkId(7009)
' k6 Y% N$ i/ T) \ v7 n - STARTED.addTalkId(7011)
Скопировать код
. U$ F. [1 q, o7 F4 ]/ h* \1 V' G/ y. j2 F& z6 P# ^/ [
|