Зарегистрируйтесь сейчас чтобы найти еще больше друзей, и получить полноценный доступ ко всем функциям сайта!
Для просмотра Вам необходимо авторизоваться Если Вы еще не зарегистрированы, перейдите по ссылке:Зарегистрироваться
x
Хроники Interlude
/ } b$ t& Y- |5 pСборка L2j( Y% E/ K, s: b; v, ?# _
Обратите внимание: в файле htm стартового NCP обязательно должна быть ссылка на квест:
0 P& Q7 v. p d6 \) m- STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста:& l! w1 P y5 i" v: `
/ ? x; p+ G" J5 z' O
- if getCount(st) >= 4 :. R. c- A" T! v2 x5 V0 v* c. V! t
- completed(st): k# J# \3 f7 U$ y# ?/ N
- return# H$ ?" Q4 a/ r6 B/ ^4 T, o# C) w8 u
! m; z- l/ ^/ _7 [% n4 e$ z( w4 k& Q- class Quest (JQuest):
- r6 L' E) y$ n0 o - def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr), D$ R0 c* j: A% m
- def onEvent (self,event,st):
# a. k7 B0 u# k( U' c7 k - id = st.getState()
, _$ F4 U* f0 g - if id == CREATED : st.setState(STARTED)! S) n! z1 t7 c5 ]
- elif id == COMPLETED: pass9 W; Z# D: B. X1 m/ }
- elif id == STARTED : check(st), N5 ^, @! ]# _- K b1 j. K) Q
- return( M5 q' e) ~8 T' g
8 p& _& u/ k% l+ C# ^- QUEST = Quest(201,"Tutorial", "Tutorial quest") S1 V( Z3 d2 l# P- h7 N! F" k
- CREATED = State('Start', QUEST)
4 d2 H' o* H, V2 L - STARTED = State('Started', QUEST)
; O4 `, T9 H6 Q% f/ o0 i+ L - COMPLETED = State('Completed', QUEST)$ L; L3 y7 X! b, P
- , Z0 O& C M0 }5 Y
- QUEST.setInitialState(CREATED)
% O# M8 B! I; I* B, ` - QUEST.addStartNpc(7056)5 q# T3 Y( c5 _1 u7 ?% |
- STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код Теперь рассмотрим, как это работает.
. o V: ^9 N# O2 ~6 iИгрок подходит к начальному NCP (в данном случае 7056), нажимает на «Quest». Квест будет создан и состояние квеста перейдет к CREATED и игроку будет показана страничка Start.htm с описанием квеста. Тогда метод onEvent, поле открытия странички Start.htm переведет состояние квеста в STARTED и игроку будет показана страничка Started.htm, где будет опсание того, как найти keltirs и .т.д.
( u: }# L# B0 _& s0 p3 Z) s4 U% i4 F* j- W5 {
, f1 |6 `: M4 {& Z- D
При состоянии STARTED будет зарегистрирован дроп «fangs» при убийстве keltirs. Игрок может вернуться к стартовому NCP и спросить о квесте – метод onEvent будет вызван снова. Если у игрока не хватает необходимого количества предметов, то метод check() не переведет квест в следующее состояние и Started.htm будет показана снова. Но если игрок собрал необходимее количество предметов (в данном случае 4 клыка), то метод check() вызовет метод completed() который переведет квест в новое состояние COMPLETED, заберет все клыки, даст карту мира, т.к. это награда за квест, покажет Completed.htm и завершит квест.
$ \& e3 T" W- v5 e
( @. u" W+ Y2 M! Z& M# R
1 V2 E8 \( I+ {" fТеперь давайте сделаем наш квест более похожим на то, что он должен из себя представлять.4 @; y* m \" @2 \# B6 p. L
Прежде всего у нас есть 3 метода для объявления их в Яве – onTalk, onKill и onEvent. Если методы onTalk и onKill не объявлены, то за них все будет делать метод onEvent, т.е. определять квестовых монстров и вызывать диалоги NCP. Есть примечание, методы onTalk и onKill будут вызывать только диалоги с NCP в зависимости от текущего состояния квеста. Метод onKill будет вызываться только тогда, когда мы убиваем квестового монстра.8 N. @3 x# J0 K
. }$ v8 @0 D+ u0 H2 q8 _# y7 `5 {
( l, W: H) g2 j6 N8 f
Давайте рассмотрим как вызывается метод onKill при убийстве keltir в состоянии квеста STARTED:# G- m7 U9 V m0 I. G
- STARTED.addKillId(KELTIR_NPC_ID)
Скопировать код и метод onKill в классе Quest:
! v: r8 I$ B/ C" m. H! g
6 N$ b: Y. u* n6 _- class Quest (JQuest):
3 e/ g# _" T" s' u; G - ...
. s; y/ [' g6 F. C' [( G/ B - def onKill (self,npcId,st):# O' v$ t# l" G5 {2 C
- if npcId == KELTIR_NPC_ID:5 g4 l% R% M" z* i: Y+ o
- n = getCount(st)
/ H3 l, @: Y# A" ]+ M - if n == 0:
" ?' U, C5 p; D9 Y; |9 h - return "Chat0.htm"/ x( G5 ~ t) F0 S* v4 W \ K% \- h
- elif n == 1:
2 b; G! O1 c+ m" G8 D; O - return "Chat1.htm"
; o) j+ b1 d6 P$ x9 N5 f. v! G - elif n >= 4:5 F/ \8 Z) {: g9 d# H% Y7 x7 g* ^" i% a
- return "Chat4.htm"
/ Z9 F3 S q: B5 F6 y - return "Collected "+str(n)+" of 4 fangs", k: J( n' m+ a% ? S4 ?
- return
Скопировать код Метод onKill (а так же метод onTalk) имеет следующие параметры:
# W# h0 m9 x0 B! }9 W7 l. H$ w0 b1 R7 ~6 }5 {$ [" ~
: p5 w5 y6 b% Q7 D% V• self – квест# Z' v7 l9 i) p& p
• npcId – ID NCP, которого мы должны убивать (если это метод onTalk, то ID того NCP, с которым мы должны поговорить).* F. [/ M! b; n( f' z
• st – текущее состояние игрока.
: [% f! [" u& n1 \- Q/ E- U7 \" g; O- O2 [
+ D7 C- I( N5 u( @
В этом методе мы проверяем и отмечаем, является ли убитый NCP keltir’ом. В основном эта проверка не нужна, т.к. у нас только KELTIR_NPC_ID.
( | Y% d* \( ?& _1 [1 `& I1 @& P1 i
& B2 j7 Q1 f3 H2 z( \, E
Затем проверяем количество предметов (в данном случае количество клыков), и если их вообще нет, то возвращаем строку "Chat0.htm", если только один предмет, то возвращаем строку "Chat1.htm", если же предметов 4 или больше, то "Chat4.htm". Если строка возвращена из методов onEvent, onKill или onTalk, то сервер покажет соответствующие htm. В Chat0.htm может иметь следующий текст: «Вы не имеете ни одного клыка, возвращайтесь позже, когда соберете 4 штуки и бла, бла, бла…», в Chat1.htm может быть следующий текст: «У Вас всего 1 клык, по этому соберите еще…». В Chat4.htm – «Вы собрали необходимое количество предметов, возвращайтесь к вашему тренеру, что бы завершить квест…»
% c1 j: P; y3 V9 I( y
% L, _+ ?' E2 m9 S, |2 `% t- W. p
Примечание: если в строка return начинается с "<html>", то будет показана страничка html с текстом, который стоит далее. Так вместо:- g$ U. P& q( p6 O x# l# o
return "Chat4.htm" q+ T# I4 a' a
E( s/ V2 U6 J( u( c3 t* V P: e8 l9 o0 O& s$ C! ?
можно поставить:
5 B- A. [; W. [* l) g- return "<html><body>Return to your trainer to complete the quest</body></html>"
Скопировать код Так же если строка заканчивается без .htm или в начале нет <html>, то текст будет выведен, как системное сообщение в окне чата. В нашем случае мы сделаем так, что бы при каждом убийстве keltik выводилось системное сообщение: «Собрано N из 4-х клыков».9 K; ?" h6 D% s. D8 T+ F
9 L W1 _6 n l3 d* U
' \( f2 T$ _# l2 Q* H) P& I2 H% gНаш код для onKill имеет один недостаток. Он будет постоянно показывать Chat0.htm, Chat1.htm и Chat4.htm, нам же необходимо, что бы Chat0.htm и Chat1.htm показывались только один раз. Как нам это сделать? С помощью переменных.- r' A4 Y* V. H# a2 w
6 J; w ~2 ]) X7 A: y
( Y: T. s& B( r. s) ?В каждом квесте строки могут храниться с помощью переменных. Эти переменные сохраняются в Вашей БД. В каждом методе мы можем назначить, прочитать и удалить переменные. Давайте изменим метод onKill, так что бы каждый диалог вызывался только один раз.
8 G# T% m' p! }$ A* V- g+ S- def onKill (self,npcId,st):
( F' \! y6 R/ A" c8 e9 I - if npcId == KELTIR_NPC_ID:. E' ~! u0 D" d6 r- P
- n = getCount(st)+ H; p @4 {) o! P1 d
- if n == 0:
b* H3 i9 C. Z4 U" [. L - if st.get('chat0') == None :
$ }+ z) A' R9 z4 B2 P! V - st.set("chat0", "true"), f" }4 m+ ?0 f( ~6 ~
- return "Chat0.htm"8 _( _7 h5 h2 T3 x' G/ i9 b( q2 p
- elif n == 1:& L e5 a1 z( \8 u5 O$ h2 ^* y2 e
- if st.get('chat1') == None :
# R5 g5 J5 d K( q# r4 u* _2 _ - st.set("chat1", "true")
. {/ v* g4 d, y5 O9 m* \) O - return "Chat1.htm"
* n- J+ K- j5 H- ^' e - elif n >= 4:+ k- \; t) V1 W7 U7 H( {
- return "Chat4.htm": U3 F" e9 s7 V, F! c% H j
- return "Collected "+str(n)+" of 4 fangs"
+ u2 y' i: x& U! O) H2 h - return
Скопировать код Если у игрока нет клыков (n=0), то мы получаем занчение переменной 'chat0'. Когда метод onKill вызван в первый раз, то пока ни каких переменных не имеется и python возвращает значение None. В этом случае объявляется переменная и показывается диалог Chat0.htm. Когда мы убиваем keltir, но не получаем с него клык, функция st.get('chat0') возвращает строку true, а не None. И во второй раз окно с Chat0.htm не появится, но в окне чата появится строчка «Collected 0 of 4 fangs». По тому же принципу сделано и с Chat1.htm.- j0 _8 |. [3 I
. y6 M$ u. x) T- J7 v1 A( I8 a
! Q Z% w0 R1 QВот конечный рабочий вариант квеста:$ {+ n2 L( L% }- D$ z
- import sys
& p; s3 D8 X# G( Q9 X* S4 [4 Y3 U3 y - from net.sf.l2j.gameserver.model.quest import State
( e! ]. e! j( z - from net.sf.l2j.gameserver.model.quest import QuestState
8 Q, C' J( V9 i1 C+ T, d, f& G2 S - from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest
$ j! Z+ {" j* d6 n5 ~
% i1 c$ o) B2 K6 y- l' L3 a5 y- KELTIR_NPC_ID = 12082: h. l5 p* L5 z/ Y& u
- FANGS_ITEM_ID = 18590 h" A2 `( }! r$ N0 u* L% V
- DROP_RATE = 500000
$ y3 W/ [7 H: J0 K) O
- f" v, n( [+ }( i- WORLD_MAP_ITEM_ID = 1665" d% S2 Y. }6 l3 u* c
- / s3 U9 e" H6 d5 D
- def getCount(st) :
! B$ L5 p! P3 i# x; D9 j - return st.getQuestItemsCount(FANGS_ITEM_ID)
) h, ~* E7 L1 e/ H& x
6 e" Z( ^# ~9 W; ^, b8 s; @* o- def completed(st) :1 J' h, f: J; W
- st.setState(COMPLETED)! p! A7 X" Y6 l$ ? t
- st.clearQuestDrops()
) U# }+ f) a2 f( P1 ~ - st.takeItems(FANGS_ITEM_ID,-1)- f4 c2 z/ n( K9 N# J$ F9 N* [
- st.giveItems(WORLD_MAP_ITEM_ID,1)1 o$ T# J" d, R) N$ A. \1 c
- st.exitQuest(False)
6 }3 L3 C" l) [2 C! H0 T8 V) b - return
0 S; c7 c4 ?* i$ {" h! R
' h J, _# y( F: @" H" u" f, S( m8 J- def check(st) :
5 R& e, L, m1 ]- U - if getCount(st) >= 4 :" x5 A( e! v Z0 {+ P/ H7 ?
- completed(st)0 d2 b$ @, I! Y( y3 f& e( |1 r. S
- return
) [% j# {3 Q5 ]. o1 j
5 \4 A# C1 r5 x. J$ V- class Quest (JQuest):
3 b: _( J d* ^) e& E
/ x; Z6 b8 G: u* k& ~# {/ j- def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)2 |3 x' P! f; K G- j. k
- ( o) ~2 q' |4 |4 k& u. o' I1 a8 w
- def onEvent (self,event,st):
3 l1 B* S- i9 t/ [" E8 G# ~$ H - id = st.getState()6 z# I0 e4 S2 S- | V+ w4 Z
- if id == CREATED : st.setState(STARTED)
8 r5 j4 Z9 H; d; v7 v/ q8 Q - elif id == COMPLETED: pass
) G( H* x, } l, {" e - elif id == STARTED : check(st)
; j' {. o. Z5 P/ J2 \) S8 O - return3 t# _( f, a0 }; ^. ~
1 z$ B2 E2 K/ D2 }- def onKill (self,npcId,st):
" m' F5 ]8 R; P6 [ - if npcId == KELTIR_NPC_ID:
* \- a% w3 Q* D; M5 w2 C) r9 J# @4 `7 j - n = getCount(st)
) T, C' R4 w! r& p6 \ - if n == 0:
8 Z, N3 C4 j5 `( r! ?+ [ - if st.get('chat0') == None :
8 ^0 Y* O5 D' M4 j; K( V9 d - st.set("chat0", "true")
& m3 b4 b" U" U+ v+ |$ B - return "Chat0.htm"
- w3 z8 s( |, H0 l - elif n == 1:2 L0 _+ ~6 u: x
- if st.get('chat1') == None :* w, z8 ?/ h# n4 f0 s+ V8 o
- st.set("chat1", "true")$ W" W! M( ?( v! I- { \
- return "Chat1.htm"
% e2 h+ W, [4 [ V - elif n >= 4:
2 e/ @% Z) ` Z7 _/ q - return "Chat4.htm"4 E$ c. p- I2 P9 s4 f4 | ~
- return "Collect "+str(n)+" of 4 fangs"
, d! A! z5 c" W; P" W - return
( v. W& U8 L; K$ @' N - 6 j$ e* `- G$ _( B l! z! W0 s5 V4 E3 O
- QUEST = Quest(201, "Tutorial", "Tutorial quest")
7 n; c& D( Z0 ?% Z - CREATED = State('Start', QUEST)
8 h& Q8 i8 l4 U - STARTED = State('Started', QUEST)
5 o/ i$ }# A! F, ~7 \4 o - COMPLETED = State('Completed', QUEST)- o2 n8 l' y' p
- % ~4 W, Y2 q( K0 D" c
- QUEST.setInitialState(CREATED); F A- _, r+ T3 _4 Z1 q. W+ m
- QUEST.addStartNpc(7056)
|4 R. v3 A" q3 O- i! m2 l - QUEST.addStartNpc(7012)
( ]* ~ @" h. b; s) t# { - QUEST.addStartNpc(7009)
$ x! z0 |- A; _ - QUEST.addStartNpc(7011)
9 d. w7 F5 D- o- x% h7 h% u - 1 }6 j5 q! _7 P8 p8 r% n$ g* D
- STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)* h8 h9 x; q$ k1 V2 J
- STARTED.addKillId(KELTIR_NPC_ID)! x- H6 \5 y4 p9 v# W
- STARTED.addTalkId(7056)+ [& ]4 c) n" Z2 Z( `! y+ w, z! j
- STARTED.addTalkI d(7012)
, W) e9 |! m6 g- q - STARTED.addTalkId(7009)
5 ~% ^; X2 t9 `( D) o, i. H - STARTED.addTalkId(7011)
Скопировать код
9 V' h: A5 T( G* r5 e( W* [! K
1 M( I; q( }) d, ]6 f. _. e* f% M: A |