Зарегистрируйтесь сейчас чтобы найти еще больше друзей, и получить полноценный доступ ко всем функциям сайта!
Для просмотра Вам необходимо авторизоваться Если Вы еще не зарегистрированы, перейдите по ссылке:Зарегистрироваться
x
Хроники Interlude
. O, `, z4 L/ m) F7 w$ p6 I* R$ P& GСборка L2j, [- A- e' n D3 i; w0 H2 \, t: h
Обратите внимание: в файле htm стартового NCP обязательно должна быть ссылка на квест:
; c; S5 y9 ^4 c* W0 S1 W+ D- STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста:- U( ~( S6 K4 A: N, b7 z4 a3 }3 N
+ |3 s: _0 K; p; q+ Q9 |
- if getCount(st) >= 4 :/ J: E9 S+ i, R2 g5 h& f. S% ~
- completed(st)1 b, w& k( o" @+ v$ Z' T7 B
- return& {- k" b) r; d! Q$ E4 U0 w, w" m7 h
) A$ P7 g# L4 Q5 O* l+ a2 t- class Quest (JQuest):
, q' {% |2 _$ I% F2 u# ~5 w u8 x$ g - def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)* B0 z# ?- g- v% W: l0 O
- def onEvent (self,event,st):2 {! p; C9 f6 g3 y
- id = st.getState()! {% N1 ~( k5 ]* q
- if id == CREATED : st.setState(STARTED)
5 ?6 F# b+ A% {$ e - elif id == COMPLETED: pass
8 \. d# J. I" [( S" \. v - elif id == STARTED : check(st)
, Y. M, T2 Q6 J1 F - return! p R& {2 Z# v. C3 P) ]
- 8 t4 j: {6 Z, t1 p* [. k/ V
- QUEST = Quest(201,"Tutorial", "Tutorial quest")% y6 w. n; g! W0 u; Y
- CREATED = State('Start', QUEST)
Z! O8 f; i# }8 j - STARTED = State('Started', QUEST)$ E+ U5 _9 N; U Y
- COMPLETED = State('Completed', QUEST)
: `9 s- q0 Q: I7 v+ l - 9 d; j1 Q; A+ r9 b6 w! I3 f N6 T+ h4 o, O
- QUEST.setInitialState(CREATED)+ C" J; k5 V" r6 q2 R& N' F) l$ h
- QUEST.addStartNpc(7056)
1 F, B/ Z- u/ R6 b* L - STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код Теперь рассмотрим, как это работает.
! V# i1 l# E% O; } AИгрок подходит к начальному NCP (в данном случае 7056), нажимает на «Quest». Квест будет создан и состояние квеста перейдет к CREATED и игроку будет показана страничка Start.htm с описанием квеста. Тогда метод onEvent, поле открытия странички Start.htm переведет состояние квеста в STARTED и игроку будет показана страничка Started.htm, где будет опсание того, как найти keltirs и .т.д.# O( g4 `, V) U7 u5 E
; Z) j6 s6 q) u2 X! J' L1 V D, {+ ?- `6 w; T
При состоянии STARTED будет зарегистрирован дроп «fangs» при убийстве keltirs. Игрок может вернуться к стартовому NCP и спросить о квесте – метод onEvent будет вызван снова. Если у игрока не хватает необходимого количества предметов, то метод check() не переведет квест в следующее состояние и Started.htm будет показана снова. Но если игрок собрал необходимее количество предметов (в данном случае 4 клыка), то метод check() вызовет метод completed() который переведет квест в новое состояние COMPLETED, заберет все клыки, даст карту мира, т.к. это награда за квест, покажет Completed.htm и завершит квест.
% e8 W. w6 X2 r7 _6 L2 }& B# O2 R( F2 u' Q
2 x2 q# X, ?" E% Z3 b+ I
Теперь давайте сделаем наш квест более похожим на то, что он должен из себя представлять.1 @0 d2 G8 S% R3 o+ M; I$ h
Прежде всего у нас есть 3 метода для объявления их в Яве – onTalk, onKill и onEvent. Если методы onTalk и onKill не объявлены, то за них все будет делать метод onEvent, т.е. определять квестовых монстров и вызывать диалоги NCP. Есть примечание, методы onTalk и onKill будут вызывать только диалоги с NCP в зависимости от текущего состояния квеста. Метод onKill будет вызываться только тогда, когда мы убиваем квестового монстра.
! o4 `4 x& m: ^4 I( J! {: B9 \! C, {# K* N3 y0 G X/ G9 ?4 c) r
+ b$ n0 }0 {) R7 d1 D+ Q
Давайте рассмотрим как вызывается метод onKill при убийстве keltir в состоянии квеста STARTED:
9 S' _! O# v7 o4 l \- STARTED.addKillId(KELTIR_NPC_ID)
Скопировать код и метод onKill в классе Quest:4 @ y( k0 \/ U8 |( U# Q( s! |. r
/ |1 N* R- V# s- class Quest (JQuest):
2 ^ q3 K6 d- i" ?1 m6 G - ...
9 N2 a) W. c+ i/ z9 a; `+ \ - def onKill (self,npcId,st):' V' i8 o1 N( s/ ]9 ?: T( u6 Y' w
- if npcId == KELTIR_NPC_ID:
- I6 h! C' D0 z. A - n = getCount(st)
`% Q! g; k0 }2 g% g - if n == 0:
# ~: w! ^% O( r5 D# z0 M& k9 j! t/ z - return "Chat0.htm"' c! D% n. b* ?6 p6 C; |) m# U' W
- elif n == 1:
( G& F2 \2 V9 E5 e. p W - return "Chat1.htm"
- k" } t5 D6 O$ k8 K6 V5 g - elif n >= 4:
- N" C/ P1 v9 g5 q! O7 |# j- E - return "Chat4.htm"! D7 |. T% o# |+ q) s; k1 s
- return "Collected "+str(n)+" of 4 fangs"
4 d4 u. J, q$ }, Z - return
Скопировать код Метод onKill (а так же метод onTalk) имеет следующие параметры:
/ I. t7 V+ b9 c* Z; P" ^! s7 M; w" G! {; B1 O3 W1 T6 z: E
$ S% c' o/ A* p+ U* a% k) }% O• self – квест! n1 N/ u4 h0 {4 g) M7 r. E, \5 O
• npcId – ID NCP, которого мы должны убивать (если это метод onTalk, то ID того NCP, с которым мы должны поговорить).
, S& A& a" s3 @: Z. l• st – текущее состояние игрока.) E, J1 _9 ]1 R9 S; ]1 B5 a
9 r; g1 e; X4 {5 K
4 Y& n; D- C, s4 Q0 B
В этом методе мы проверяем и отмечаем, является ли убитый NCP keltir’ом. В основном эта проверка не нужна, т.к. у нас только KELTIR_NPC_ID.
: D5 C4 a: n4 w* O* @( s: B# I% G3 A
8 |$ t) f z) g( ~% `1 SЗатем проверяем количество предметов (в данном случае количество клыков), и если их вообще нет, то возвращаем строку "Chat0.htm", если только один предмет, то возвращаем строку "Chat1.htm", если же предметов 4 или больше, то "Chat4.htm". Если строка возвращена из методов onEvent, onKill или onTalk, то сервер покажет соответствующие htm. В Chat0.htm может иметь следующий текст: «Вы не имеете ни одного клыка, возвращайтесь позже, когда соберете 4 штуки и бла, бла, бла…», в Chat1.htm может быть следующий текст: «У Вас всего 1 клык, по этому соберите еще…». В Chat4.htm – «Вы собрали необходимое количество предметов, возвращайтесь к вашему тренеру, что бы завершить квест…»
& G$ u/ P5 C! ?1 e' S5 r% i
1 ~% I2 S4 i2 r P* y& L% G2 l8 `' D2 B" N1 D/ T# p
Примечание: если в строка return начинается с "<html>", то будет показана страничка html с текстом, который стоит далее. Так вместо:: u+ o z" ?! K6 E$ _9 j9 ~: x1 h `- \
return "Chat4.htm"& u' s6 Z; y0 K- G! }, f! b
8 g, W: n' x3 @+ Z! K0 C* U
- w0 U+ g7 y" L" j" P: g3 zможно поставить:
/ O( \5 }) W) _ i3 p- return "<html><body>Return to your trainer to complete the quest</body></html>"
Скопировать код Так же если строка заканчивается без .htm или в начале нет <html>, то текст будет выведен, как системное сообщение в окне чата. В нашем случае мы сделаем так, что бы при каждом убийстве keltik выводилось системное сообщение: «Собрано N из 4-х клыков».
' s: O; E& q& C, {: y1 n7 p0 R( u5 d4 t; o/ X; a. P+ t+ q9 W
9 c& q7 \/ g. T1 s
Наш код для onKill имеет один недостаток. Он будет постоянно показывать Chat0.htm, Chat1.htm и Chat4.htm, нам же необходимо, что бы Chat0.htm и Chat1.htm показывались только один раз. Как нам это сделать? С помощью переменных.# b8 M1 ?2 B, r9 F) Q9 t. u& V- O
! m- w( }0 C7 ~+ D8 y/ D7 O
8 `4 V4 K9 s4 A9 @4 D# hВ каждом квесте строки могут храниться с помощью переменных. Эти переменные сохраняются в Вашей БД. В каждом методе мы можем назначить, прочитать и удалить переменные. Давайте изменим метод onKill, так что бы каждый диалог вызывался только один раз. H* P2 ~2 k/ Z* C8 V
- def onKill (self,npcId,st):
, L9 e: O# S/ C7 j g0 O5 e8 [$ P - if npcId == KELTIR_NPC_ID:1 u' @% w' l" i9 k
- n = getCount(st)7 G; c# Q8 A# }' c$ m, B
- if n == 0:
, f+ j: N* U9 y# p4 E8 Z2 X - if st.get('chat0') == None :# I5 q2 G1 z5 K- v0 i- q( R
- st.set("chat0", "true")4 \* k- {( Q/ l
- return "Chat0.htm"* n% M+ f* q1 g$ ]/ e7 F
- elif n == 1:* p$ i" K7 u6 R& H3 C
- if st.get('chat1') == None :
* Y4 i/ G% \' P6 u( i( w! h& r - st.set("chat1", "true")
7 ]& M W. }- d6 J1 z3 ] - return "Chat1.htm"7 W# p6 [* c0 X7 R
- elif n >= 4:6 X1 r2 q3 Q5 U* r8 P
- return "Chat4.htm"& P2 I- L$ j; D, n/ K- E9 F5 p
- return "Collected "+str(n)+" of 4 fangs"
' p R5 f8 H7 q& N3 S* b$ M - 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# Y$ T/ w' F8 j2 z
7 o0 x! @6 R6 e6 H9 ]' k8 Y
! {; w+ S; ], S5 `& W, iВот конечный рабочий вариант квеста:
8 C% ~/ x7 d4 E+ R' @, ^- import sys. C0 Q K- {2 k8 S: r
- from net.sf.l2j.gameserver.model.quest import State
4 ]( j2 |( Y' P+ q1 F - from net.sf.l2j.gameserver.model.quest import QuestState
& H) u# T& c, S+ c9 D - from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest
% e% n% n9 n: n N2 o4 R
" `& B; I" b) E; Y- KELTIR_NPC_ID = 12082
2 N% v# ~- O* C4 K6 l4 n" r* ^ - FANGS_ITEM_ID = 1859
7 {9 \! W/ n5 x3 F - DROP_RATE = 500000
F/ _$ p3 I7 t+ l9 d, X& ` - 3 l q) }( w4 X2 @9 z m
- WORLD_MAP_ITEM_ID = 1665: {* U! Q& e, z
+ O; a0 e( w, n- def getCount(st) :% m. d9 z( a. V5 _
- return st.getQuestItemsCount(FANGS_ITEM_ID)
/ t# P2 E2 Z1 j; m) R7 g - 3 q2 m9 k1 I. r# X$ w7 o5 P# [; ]
- def completed(st) :
% k: F" } b8 L - st.setState(COMPLETED)
& N5 o$ Z" X- Y7 t% | - st.clearQuestDrops()
1 u& s+ `' a3 w3 O+ ?; A+ t5 {3 M - st.takeItems(FANGS_ITEM_ID,-1)
3 e/ `) J1 k8 k4 E) x% [9 N - st.giveItems(WORLD_MAP_ITEM_ID,1): g3 L# v, q$ M$ ?/ P X# _
- st.exitQuest(False)) s% t/ B, g. F5 P) k
- return# }0 ^4 g/ c8 I' f0 K: ~
) V$ r7 Z% o: U2 n7 j) B0 s" y8 q( T. ^- def check(st) :
$ a+ a, o! ~" @8 i+ m - if getCount(st) >= 4 :7 m/ I! \4 @+ N4 I" t
- completed(st)
3 c/ E# k* E8 @# o - return
9 U! O9 ~% O/ s9 J - $ S+ \, k& h# p4 `! Z; m
- class Quest (JQuest):
0 e9 z: k) J# q
6 W: T3 _; f3 U6 E0 ]' a+ @! M- def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)/ }: x9 [- P" K) `0 E( \6 w; ]
- 9 W8 b( R1 @- i2 C: T+ ?1 n
- def onEvent (self,event,st):8 B: O: |9 ?* e+ h3 [
- id = st.getState()
; f+ P/ l) s* O0 ] - if id == CREATED : st.setState(STARTED)
# Y$ k( A3 V2 V# A/ I - elif id == COMPLETED: pass
8 T( {& s, `/ \6 T - elif id == STARTED : check(st)0 ?+ _! y' F s; Z) c
- return
2 g8 Q$ G% t* c) d+ N - / _$ i: r; ~0 Z8 ^3 _/ ~
- def onKill (self,npcId,st):
5 Z5 ~( V7 a( ` - if npcId == KELTIR_NPC_ID:0 r' C H" X3 K! ? x0 B5 x
- n = getCount(st)
0 @3 T8 @! ?6 c2 Y p9 ?6 D - if n == 0:3 v; V# ?9 {1 L! J3 u) i% I5 E s5 I1 j3 r
- if st.get('chat0') == None :( p2 P& t2 ^7 Y, v: \5 n& J+ m" ~
- st.set("chat0", "true")
. |5 {2 A$ v, m8 J6 w/ A - return "Chat0.htm"
; _2 g9 C2 @( Y - elif n == 1:
' | p" g6 E% L, N$ o/ h - if st.get('chat1') == None :, d/ k# l) A0 r' J
- st.set("chat1", "true")/ k" U7 z. k1 r A0 @8 [- ?/ y$ i
- return "Chat1.htm"
% w" L0 [. K8 H1 [) S1 A - elif n >= 4:
( M. @2 P6 U) g8 v0 r - return "Chat4.htm"
) M8 y, @$ w0 \# [* L; {4 q7 | - return "Collect "+str(n)+" of 4 fangs"( I& O+ G0 N7 W- E& ^& A: U
- return3 a) ~$ A- A. C; ~) Q+ d
- - P- D# ~2 H" d/ E+ z3 S) ]
- QUEST = Quest(201, "Tutorial", "Tutorial quest")
# X [7 [9 b- }2 E; h3 j4 [ - CREATED = State('Start', QUEST)
9 I8 n: F3 D7 b9 |% e+ u - STARTED = State('Started', QUEST)5 U5 W# h% H$ @) T U+ X
- COMPLETED = State('Completed', QUEST)) U( M/ t# q' n$ I5 d7 K" J0 I' }
- 9 N% h1 P8 p8 x2 a1 r& ^) N* [
- QUEST.setInitialState(CREATED): I) p4 F# K+ L' K- l6 R) K/ \
- QUEST.addStartNpc(7056)
4 G& K: f( d1 R4 j1 `" ^8 j - QUEST.addStartNpc(7012)7 w/ P2 h' a7 C* i" f1 U
- QUEST.addStartNpc(7009)$ d7 H/ W S+ y5 w# K* V- O* X5 U
- QUEST.addStartNpc(7011), q, u) e- p6 V8 a4 e
- ( z# r I6 W! W5 u" L1 s% a7 _2 Y% n
- STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
8 `+ P! [3 z' t9 V - STARTED.addKillId(KELTIR_NPC_ID)
, ^4 L6 s8 s4 F G - STARTED.addTalkId(7056): F9 Q, L k. f% ^: ?2 E @
- STARTED.addTalkI d(7012)! j% z" L. f9 ?2 V7 ?) T8 h
- STARTED.addTalkId(7009)
5 l5 c6 }# X% k - STARTED.addTalkId(7011)
Скопировать код ; A6 A l0 `1 C+ }4 W) k& u
/ B8 z! B, K1 {( U
|