Зарегистрируйтесь сейчас чтобы найти еще больше друзей, и получить полноценный доступ ко всем функциям сайта!
Для просмотра Вам необходимо авторизоваться Если Вы еще не зарегистрированы, перейдите по ссылке:Зарегистрироваться
x
Хроники Interlude" Y3 f( j) J; p ?1 g7 r
Сборка L2j& [9 @) |* U& ^
Обратите внимание: в файле htm стартового NCP обязательно должна быть ссылка на квест:
3 h; K3 u: F3 V* X0 {# _5 ~- STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста:* _' F/ {) M1 |) `& i, w, S
y+ |/ L& K+ P- u. W" H e' H- if getCount(st) >= 4 :4 ^$ t4 g/ z! P
- completed(st)
3 v- y+ Z+ k* S* w3 [+ M - return% {1 t# M+ A+ y
- 6 f' d+ T$ ?# U- \
- class Quest (JQuest):
7 P; T* \/ \: D# v: @) b" A4 { - def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)
5 u7 {$ K3 r0 b - def onEvent (self,event,st):0 G8 P$ _* X* Q+ W* `
- id = st.getState()0 j9 F6 ]7 U8 N* ^
- if id == CREATED : st.setState(STARTED)
- R( p; B, k; ~+ T. ]' Q8 J+ { - elif id == COMPLETED: pass0 O' [1 [* N5 \( {7 @( U' F2 I5 }
- elif id == STARTED : check(st)
9 c5 s0 A- i! s% q5 i& p+ {# I - return9 T& u/ }7 K5 b9 i/ w
8 r1 K1 q) ]$ ]9 j- N- QUEST = Quest(201,"Tutorial", "Tutorial quest")0 b+ n0 H0 b+ j# n
- CREATED = State('Start', QUEST)
2 v+ X; W0 e9 c8 q# Q+ S6 p - STARTED = State('Started', QUEST)
- Y! H* ^1 k. n" \' k - COMPLETED = State('Completed', QUEST). }' f3 f7 ?2 q
& n' s3 d. y" y$ F4 j- QUEST.setInitialState(CREATED)& U& g Y3 t# z8 ]" {( t
- QUEST.addStartNpc(7056)% r) n. K- b3 H
- STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код Теперь рассмотрим, как это работает.
* z: y& d- p$ BИгрок подходит к начальному NCP (в данном случае 7056), нажимает на «Quest». Квест будет создан и состояние квеста перейдет к CREATED и игроку будет показана страничка Start.htm с описанием квеста. Тогда метод onEvent, поле открытия странички Start.htm переведет состояние квеста в STARTED и игроку будет показана страничка Started.htm, где будет опсание того, как найти keltirs и .т.д.
3 H2 s% d" d" N8 n+ Z, j& u+ ]% W1 T9 j, H! V
1 B/ Y, ?+ R# [6 Y% T: h
При состоянии STARTED будет зарегистрирован дроп «fangs» при убийстве keltirs. Игрок может вернуться к стартовому NCP и спросить о квесте – метод onEvent будет вызван снова. Если у игрока не хватает необходимого количества предметов, то метод check() не переведет квест в следующее состояние и Started.htm будет показана снова. Но если игрок собрал необходимее количество предметов (в данном случае 4 клыка), то метод check() вызовет метод completed() который переведет квест в новое состояние COMPLETED, заберет все клыки, даст карту мира, т.к. это награда за квест, покажет Completed.htm и завершит квест.% \. o1 ]9 W( i: O1 O6 T' W
# Q# @ P; b3 I; l5 {$ X
9 R2 S/ a0 g: K
Теперь давайте сделаем наш квест более похожим на то, что он должен из себя представлять.8 X7 ]: x1 F& A+ L
Прежде всего у нас есть 3 метода для объявления их в Яве – onTalk, onKill и onEvent. Если методы onTalk и onKill не объявлены, то за них все будет делать метод onEvent, т.е. определять квестовых монстров и вызывать диалоги NCP. Есть примечание, методы onTalk и onKill будут вызывать только диалоги с NCP в зависимости от текущего состояния квеста. Метод onKill будет вызываться только тогда, когда мы убиваем квестового монстра.3 Q9 @0 p" Y- t/ B1 f
- r2 N! g$ Y. ^) |
; ~( G, S) {; W7 f; m" |Давайте рассмотрим как вызывается метод onKill при убийстве keltir в состоянии квеста STARTED:/ s; ]$ e4 i% [$ U+ I
- STARTED.addKillId(KELTIR_NPC_ID)
Скопировать код и метод onKill в классе Quest:- e& C' F' R. r
0 Q( E. L8 d+ h! m0 w9 j- v
- class Quest (JQuest):6 ~$ j9 f J3 N8 q
- ...
# i# X( p% j2 l. m& g - def onKill (self,npcId,st):
6 c% j' x* B! w0 I) H - if npcId == KELTIR_NPC_ID:
0 s: J; `8 B3 _% v - n = getCount(st)
) T3 y$ |+ v5 l! `- r% f H - if n == 0:
) w' \ c! d' i( {4 b0 t" e4 }5 g8 U - return "Chat0.htm"
! c$ r9 L4 c0 ]# D - elif n == 1:
& i: L9 V5 d, A - return "Chat1.htm"
9 [( b/ G" H1 S6 L* E - elif n >= 4:3 Z/ G7 c: n8 D/ Y3 m
- return "Chat4.htm"
& x& j8 \8 _" k6 w! P8 } - return "Collected "+str(n)+" of 4 fangs": p$ N2 B) s: H9 q0 [* F4 J/ t
- return
Скопировать код Метод onKill (а так же метод onTalk) имеет следующие параметры:0 R' [3 w( F4 ?1 ]4 F9 e
$ Q" I U: K3 O$ T
; T7 y( O3 F) @; z0 l1 c• self – квест
( }$ O# A: Z2 r# {• npcId – ID NCP, которого мы должны убивать (если это метод onTalk, то ID того NCP, с которым мы должны поговорить).8 ~, C. U1 m, O( W! n \* m: K8 X
• st – текущее состояние игрока.% i+ X5 P% W# G' h x
- `! n8 `; Y) D4 ^, w4 o; E) [8 i) g
В этом методе мы проверяем и отмечаем, является ли убитый NCP keltir’ом. В основном эта проверка не нужна, т.к. у нас только KELTIR_NPC_ID.
. l4 s+ X) P$ e9 E4 m! `$ e% d/ S# C8 Q. t& j0 U5 u$ x
" M, p* v' K* d$ X
Затем проверяем количество предметов (в данном случае количество клыков), и если их вообще нет, то возвращаем строку "Chat0.htm", если только один предмет, то возвращаем строку "Chat1.htm", если же предметов 4 или больше, то "Chat4.htm". Если строка возвращена из методов onEvent, onKill или onTalk, то сервер покажет соответствующие htm. В Chat0.htm может иметь следующий текст: «Вы не имеете ни одного клыка, возвращайтесь позже, когда соберете 4 штуки и бла, бла, бла…», в Chat1.htm может быть следующий текст: «У Вас всего 1 клык, по этому соберите еще…». В Chat4.htm – «Вы собрали необходимое количество предметов, возвращайтесь к вашему тренеру, что бы завершить квест…»/ F' Z. H$ s6 n' Q% E, [2 A
! H% j; a* w4 D9 q7 W% z7 o0 O/ @+ \" T$ N7 K( x
Примечание: если в строка return начинается с "<html>", то будет показана страничка html с текстом, который стоит далее. Так вместо:
+ e% h) t6 j- L+ G; Y, x0 Areturn "Chat4.htm"# p: m2 ^% h# L5 D. F1 o* t4 H
* |8 O1 p. f! \. |( s
+ e, F6 K+ I+ ]- Iможно поставить:! M% s' h- g( r4 T. |7 y
- return "<html><body>Return to your trainer to complete the quest</body></html>"
Скопировать код Так же если строка заканчивается без .htm или в начале нет <html>, то текст будет выведен, как системное сообщение в окне чата. В нашем случае мы сделаем так, что бы при каждом убийстве keltik выводилось системное сообщение: «Собрано N из 4-х клыков».
2 l5 ?' i% Y/ K) L4 _% K
5 S. K' F4 b2 L' p* U* d- \! @! U$ U: P/ D& `/ l: h
Наш код для onKill имеет один недостаток. Он будет постоянно показывать Chat0.htm, Chat1.htm и Chat4.htm, нам же необходимо, что бы Chat0.htm и Chat1.htm показывались только один раз. Как нам это сделать? С помощью переменных.
# y9 G' p$ ~. w0 B4 J
7 P) n4 H- G4 k, I; T5 u" S' J, r: U' v6 [* a6 f0 M+ \$ [) `
В каждом квесте строки могут храниться с помощью переменных. Эти переменные сохраняются в Вашей БД. В каждом методе мы можем назначить, прочитать и удалить переменные. Давайте изменим метод onKill, так что бы каждый диалог вызывался только один раз.) K6 ^% X, S& i1 e& \
- def onKill (self,npcId,st):: G' x) t" J) e0 ]4 m
- if npcId == KELTIR_NPC_ID:
& K- s9 I: n. T, G - n = getCount(st)
, }# ~5 h; V+ L5 |5 G7 D - if n == 0:
% Y z4 G9 E, [ a - if st.get('chat0') == None :* I7 i* x, G7 o# b7 u
- st.set("chat0", "true")! G3 D* Q2 s) w6 ?. z" V! i
- return "Chat0.htm"
3 q: _8 p" c2 T1 m3 F( y3 [ - elif n == 1:+ R# u1 ~4 y$ y4 F) J% v
- if st.get('chat1') == None :
7 m* F0 D# Q1 L u! k. K - st.set("chat1", "true")
2 \" Z+ a1 F. a- v, a# t& M& ^ - return "Chat1.htm"
8 g: v2 i; G* j/ l8 x2 Q4 u9 o! } - elif n >= 4:/ n! f% x' \; C1 Y' t
- return "Chat4.htm"
5 n: g, |" t9 S) T - return "Collected "+str(n)+" of 4 fangs"5 s# a1 T5 [. h# u1 f# E* B
- return
Скопировать код Если у игрока нет клыков (n=0), то мы получаем занчение переменной 'chat0'. Когда метод onKill вызван в первый раз, то пока ни каких переменных не имеется и python возвращает значение None. В этом случае объявляется переменная и показывается диалог Chat0.htm. Когда мы убиваем keltir, но не получаем с него клык, функция st.get('chat0') возвращает строку true, а не None. И во второй раз окно с Chat0.htm не появится, но в окне чата появится строчка «Collected 0 of 4 fangs». По тому же принципу сделано и с Chat1.htm.
$ Z( t8 m' T: u$ `/ b1 k; E4 r8 W( o$ Y4 f
6 E; z' Y6 o) A2 C+ X' NВот конечный рабочий вариант квеста:/ G0 c+ e8 [/ O+ Q
- import sys
( v. [8 o% c }, r& h - from net.sf.l2j.gameserver.model.quest import State: m' d3 P8 I8 @' _
- from net.sf.l2j.gameserver.model.quest import QuestState
" ^6 } [, l% L9 \0 {* G - from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest& Z- d# a/ b& g( y
- 5 o$ t, a& i- ~7 _
- KELTIR_NPC_ID = 12082( E4 F! v/ D0 v, L8 j }
- FANGS_ITEM_ID = 1859
# Q5 Q, \ S7 C, S* B' \ - DROP_RATE = 500000
4 A/ ^0 C5 h; k6 X/ {
4 x6 S3 ^6 w0 }; s3 z3 n* b- WORLD_MAP_ITEM_ID = 1665: v! \) L" R, s6 q5 J* h8 h* a; m
& L( u# q6 b9 {# S" Z$ U5 w- def getCount(st) :
9 f& b! t; g3 O. n9 N* N! y - return st.getQuestItemsCount(FANGS_ITEM_ID)) ^- J6 M; H- v
- a/ H. \) @+ v- E' ^
- def completed(st) :
: `7 x# }0 j$ I, y7 i - st.setState(COMPLETED)
( m) b* Z Q$ { `1 V6 s I" B - st.clearQuestDrops()
9 {$ v8 V! w; D! H% h - st.takeItems(FANGS_ITEM_ID,-1)( ?( \3 g$ b0 F; p W' m3 e
- st.giveItems(WORLD_MAP_ITEM_ID,1)7 w- O1 V- L# p1 C& {8 i9 U0 r8 `
- st.exitQuest(False)
% X6 O( R6 c! S) ]% d4 j; \ - return
! q8 r$ ?, r) z
4 P- Q& U7 m9 t! g* X9 l( J- def check(st) :, n2 G% \/ e/ S0 A
- if getCount(st) >= 4 :
* l0 J7 K) r1 T+ U# d% ~ - completed(st), t0 T: v% M9 S! L0 Q' a% f
- return6 {; n+ n" }; l6 l& E
+ q, q ?6 }2 L# L- R% V. @- class Quest (JQuest):( B7 }9 G# \, Y% K. |5 y
- ; O1 y" K1 I, f6 p7 B$ {
- def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)8 k, L8 W7 R4 K g( N6 ?
( H( b6 _% Z! B2 c+ ?- def onEvent (self,event,st):
9 S* X- m1 i5 v2 g! u7 M! G6 ? - id = st.getState()
: [" C1 J7 C* N' e - if id == CREATED : st.setState(STARTED)$ M, [/ w5 b& |2 b
- elif id == COMPLETED: pass( g4 \$ z6 E& y$ S2 ]
- elif id == STARTED : check(st)
2 l0 e5 g" Y; ^ - return8 ?) c; O0 y) g3 u
7 Y- l, k% z; T4 z% s- _- def onKill (self,npcId,st):
( [0 }, Y6 ]& ^9 j( A) { - if npcId == KELTIR_NPC_ID:
! s+ w3 M2 Q `, e$ T4 W% w- f4 V - n = getCount(st)6 ~3 D4 ~* m# ]! M7 |+ h+ |
- if n == 0:
) ^3 e7 G, V6 s& Z4 e. J5 t1 V - if st.get('chat0') == None :
1 x3 n' k& Z$ j: X7 u - st.set("chat0", "true")
+ j1 X& K# k/ V3 x2 o0 @) z - return "Chat0.htm"5 u+ w* ? Z4 B; H+ A: A z
- elif n == 1:
5 m. {! j( }) u - if st.get('chat1') == None :$ y' k' j" X5 ?/ e @
- st.set("chat1", "true")! M" g0 u6 d L# o. l+ o1 F0 v, c
- return "Chat1.htm"( s% z2 _9 \6 G5 c* g
- elif n >= 4:; `6 Z! M' d% S
- return "Chat4.htm"
% k2 }* J9 B* e; v2 I$ z: \! }% U - return "Collect "+str(n)+" of 4 fangs"' u$ t% w: q" \) r y, U
- return
* o& s9 q/ o% l4 `! `" a - 6 B9 i2 ?" J; \! h
- QUEST = Quest(201, "Tutorial", "Tutorial quest")
8 p# M& H6 Y% h. Y - CREATED = State('Start', QUEST)% Y, c# w s; o' Q# E
- STARTED = State('Started', QUEST)/ }4 F* B' j6 J5 \2 F
- COMPLETED = State('Completed', QUEST)- @; L9 J9 P$ L" l
; @7 A7 N5 _) _. |- QUEST.setInitialState(CREATED)
9 O% Z8 u. J2 g3 O+ J. F) p - QUEST.addStartNpc(7056)
! M! U8 T4 [, b6 U/ F - QUEST.addStartNpc(7012)
( {7 \0 K$ d9 D( k5 x6 Z6 x - QUEST.addStartNpc(7009)7 Y0 ?% N& P' F G% ^, ?
- QUEST.addStartNpc(7011)
4 T, i. Z% N0 l
! U% p5 c$ e+ \* N/ l% ?( M5 g: ^- STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
' l( }' B7 k3 Y8 G' @ - STARTED.addKillId(KELTIR_NPC_ID)' o" D* L4 `& i3 f2 P, I
- STARTED.addTalkId(7056)
- b, C. M, F- B R6 O8 c0 y/ p7 C7 M; h - STARTED.addTalkI d(7012)5 P, u; c0 w: N4 [$ U% S
- STARTED.addTalkId(7009)
# m4 h' e# p i9 A5 e - STARTED.addTalkId(7011)
Скопировать код / ~0 B& ]2 l4 D" N" z3 t# j
2 {* N( j7 \" F& E, t2 C |