Зарегистрируйтесь сейчас чтобы найти еще больше друзей, и получить полноценный доступ ко всем функциям сайта!
Для просмотра Вам необходимо авторизоваться Если Вы еще не зарегистрированы, перейдите по ссылке:Зарегистрироваться
x
Хроники Interlude
( @/ z$ ]0 K2 I( L: eСборка L2j/ [0 e; J6 x4 e w2 w s4 t' i& M$ M
Обратите внимание: в файле htm стартового NCP обязательно должна быть ссылка на квест:
( s- q) D; x5 A* L# k1 v1 Z- k- STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста:- X9 v0 L' `. ~6 U: J7 l
0 t2 |& K1 \" a/ y- if getCount(st) >= 4 :+ l5 I, d9 S4 m# n5 T
- completed(st)- ]$ v& z E6 R# ^5 V6 C8 T
- return
' g f8 t& I* ]* T( a* F. j8 A - & `4 {) o! i) c( W/ Y6 j
- class Quest (JQuest):
# o' E! A, O; a! t2 _! e3 } - def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)& w1 z: X% v( n
- def onEvent (self,event,st):
Q9 H; ?, a2 F8 z- s% g- \. t - id = st.getState()) |3 N' ]) I! p) Y
- if id == CREATED : st.setState(STARTED)
) p8 q4 x$ f, M5 n - elif id == COMPLETED: pass: h; e3 c5 F- V' E, J4 @3 d5 X/ k
- elif id == STARTED : check(st)% ?5 }7 {6 H" I- N8 ]! K
- return
& i0 Q* I, ~# G0 F/ D1 k1 ?1 X
4 w7 q; d# |6 V, ^2 G- QUEST = Quest(201,"Tutorial", "Tutorial quest")
G4 q. x* }1 u" y - CREATED = State('Start', QUEST)/ Y" [" [- f0 u0 \$ N1 d c" c0 I: {
- STARTED = State('Started', QUEST)
5 b* u: S' ~# F8 n; r, M! `+ ^1 N - COMPLETED = State('Completed', QUEST)( j8 V, v; v2 e1 f, I
- $ `' l; |1 ?3 q3 j B
- QUEST.setInitialState(CREATED)# A5 ~6 v' {! N
- QUEST.addStartNpc(7056)& O: o* l/ G9 {8 ^6 [
- STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код Теперь рассмотрим, как это работает.
; r9 `+ g+ w; Z. XИгрок подходит к начальному NCP (в данном случае 7056), нажимает на «Quest». Квест будет создан и состояние квеста перейдет к CREATED и игроку будет показана страничка Start.htm с описанием квеста. Тогда метод onEvent, поле открытия странички Start.htm переведет состояние квеста в STARTED и игроку будет показана страничка Started.htm, где будет опсание того, как найти keltirs и .т.д.$ X+ Y5 P" V6 s
' l3 N/ }& k1 \5 p; W
# f6 r' k: Q \* C7 o6 C1 O
При состоянии STARTED будет зарегистрирован дроп «fangs» при убийстве keltirs. Игрок может вернуться к стартовому NCP и спросить о квесте – метод onEvent будет вызван снова. Если у игрока не хватает необходимого количества предметов, то метод check() не переведет квест в следующее состояние и Started.htm будет показана снова. Но если игрок собрал необходимее количество предметов (в данном случае 4 клыка), то метод check() вызовет метод completed() который переведет квест в новое состояние COMPLETED, заберет все клыки, даст карту мира, т.к. это награда за квест, покажет Completed.htm и завершит квест.% N$ t1 [; c' S$ _1 U/ j/ O
7 @+ [; o+ [, [* K2 D9 t1 ]+ P# A9 D ]$ u+ N+ f+ g
Теперь давайте сделаем наш квест более похожим на то, что он должен из себя представлять.
7 A0 W3 V/ g! r% r3 U5 s$ h9 f* tПрежде всего у нас есть 3 метода для объявления их в Яве – onTalk, onKill и onEvent. Если методы onTalk и onKill не объявлены, то за них все будет делать метод onEvent, т.е. определять квестовых монстров и вызывать диалоги NCP. Есть примечание, методы onTalk и onKill будут вызывать только диалоги с NCP в зависимости от текущего состояния квеста. Метод onKill будет вызываться только тогда, когда мы убиваем квестового монстра.* g3 _ w% _. ~8 r2 V$ a
6 C( p2 Q" a8 L4 I& g7 L: s
% C. M4 Y3 Z1 z" n9 Z' G
Давайте рассмотрим как вызывается метод onKill при убийстве keltir в состоянии квеста STARTED:2 V: K! C/ B9 B8 _
- STARTED.addKillId(KELTIR_NPC_ID)
Скопировать код и метод onKill в классе Quest:
8 Q& x7 ~# ]4 K V K @3 `
4 W7 P9 v5 ?+ ?, q) c2 h; w# T- class Quest (JQuest):0 J$ f, H H" O0 K
- ...
' q4 N' Y D! t! x- v - def onKill (self,npcId,st):
& w. i, W* V6 n, ~. U, h - if npcId == KELTIR_NPC_ID:
8 D) C8 O [, o+ y - n = getCount(st)! ?% B" F' O1 X5 J& [2 N8 A
- if n == 0:: T7 B/ ^5 d. n. p+ ~
- return "Chat0.htm") O5 q( u, b' }0 E" N
- elif n == 1:
1 @* U1 o" G; U7 E - return "Chat1.htm": ~4 l+ z* R$ \/ v
- elif n >= 4:
6 ^. ?" v5 k4 Y/ }* E - return "Chat4.htm"* i' w# S: Y, n1 h) n0 ?: d, \. C
- return "Collected "+str(n)+" of 4 fangs"* ^: i1 O A! H7 @+ g8 W' p
- return
Скопировать код Метод onKill (а так же метод onTalk) имеет следующие параметры:& h$ H% M: W. K1 m; S8 |7 ^
- J7 w/ B+ v8 d: @
+ A4 t" A: X3 K• self – квест
$ \# l& s) f) ?- W; l• npcId – ID NCP, которого мы должны убивать (если это метод onTalk, то ID того NCP, с которым мы должны поговорить)., v) D0 F" G+ G3 ~! G, A
• st – текущее состояние игрока.
- d3 ~+ [- B. B
) D d2 V6 N2 n$ b/ ?& y8 B' V9 {" b
В этом методе мы проверяем и отмечаем, является ли убитый NCP keltir’ом. В основном эта проверка не нужна, т.к. у нас только KELTIR_NPC_ID.
8 t' w: P3 r% T/ H& E) c% |
* n9 ~3 I# p- b" A" d# D
2 m/ n, v; i/ R- PЗатем проверяем количество предметов (в данном случае количество клыков), и если их вообще нет, то возвращаем строку "Chat0.htm", если только один предмет, то возвращаем строку "Chat1.htm", если же предметов 4 или больше, то "Chat4.htm". Если строка возвращена из методов onEvent, onKill или onTalk, то сервер покажет соответствующие htm. В Chat0.htm может иметь следующий текст: «Вы не имеете ни одного клыка, возвращайтесь позже, когда соберете 4 штуки и бла, бла, бла…», в Chat1.htm может быть следующий текст: «У Вас всего 1 клык, по этому соберите еще…». В Chat4.htm – «Вы собрали необходимое количество предметов, возвращайтесь к вашему тренеру, что бы завершить квест…»
2 D6 y# U v1 ` b5 q5 x# \5 _' G7 y8 M2 g# }- X* r
" J8 d) k& S# Y. k" `& n! rПримечание: если в строка return начинается с "<html>", то будет показана страничка html с текстом, который стоит далее. Так вместо:
" U- I9 ?! F+ M" @! rreturn "Chat4.htm"' d. t" o% y3 N" A/ u2 _
$ p. D ^( Q" Y
- K# E& v4 t9 j0 C5 L
можно поставить:
5 }2 \; @8 ?5 l2 z- return "<html><body>Return to your trainer to complete the quest</body></html>"
Скопировать код Так же если строка заканчивается без .htm или в начале нет <html>, то текст будет выведен, как системное сообщение в окне чата. В нашем случае мы сделаем так, что бы при каждом убийстве keltik выводилось системное сообщение: «Собрано N из 4-х клыков».
/ m y% B; i e5 ^
' r% j5 O( D1 ]. ^4 U* d
; L7 ~+ g: z y0 ~Наш код для onKill имеет один недостаток. Он будет постоянно показывать Chat0.htm, Chat1.htm и Chat4.htm, нам же необходимо, что бы Chat0.htm и Chat1.htm показывались только один раз. Как нам это сделать? С помощью переменных.7 z+ A" I M' S0 V/ i# I
4 P9 V+ {6 t: y+ a' R
4 x6 e* y/ ]& w& a D
В каждом квесте строки могут храниться с помощью переменных. Эти переменные сохраняются в Вашей БД. В каждом методе мы можем назначить, прочитать и удалить переменные. Давайте изменим метод onKill, так что бы каждый диалог вызывался только один раз.
{3 U5 [9 d# @& }- j- def onKill (self,npcId,st):
* t W, n* l" T' X+ `7 ?. x% s' k - if npcId == KELTIR_NPC_ID:
) C* A0 D& Y2 `6 v7 a0 J - n = getCount(st)+ m5 J, J% ^% k/ E0 ~
- if n == 0:
. W; E2 e7 l* [% l: Q0 ^- } - if st.get('chat0') == None :, O7 U; k- u: m9 ]8 p
- st.set("chat0", "true")
* }' ?" W+ X8 t# w, h - return "Chat0.htm"0 X- c; Z4 f' [. A5 h' P3 b! @
- elif n == 1:
8 i0 A2 Q+ D" ?- B - if st.get('chat1') == None :; i1 w; b' ?" {- L
- st.set("chat1", "true")
# ~) p( E% q7 [- R/ V+ |" C' E( O - return "Chat1.htm"4 [& Y# F( u P! s1 _5 c
- elif n >= 4:
, k9 K* G8 P- d. n - return "Chat4.htm"
+ e0 L2 z0 n) `! C - return "Collected "+str(n)+" of 4 fangs"
6 d; X6 d+ m: c - return
Скопировать код Если у игрока нет клыков (n=0), то мы получаем занчение переменной 'chat0'. Когда метод onKill вызван в первый раз, то пока ни каких переменных не имеется и python возвращает значение None. В этом случае объявляется переменная и показывается диалог Chat0.htm. Когда мы убиваем keltir, но не получаем с него клык, функция st.get('chat0') возвращает строку true, а не None. И во второй раз окно с Chat0.htm не появится, но в окне чата появится строчка «Collected 0 of 4 fangs». По тому же принципу сделано и с Chat1.htm.$ @' c* P; D$ L# O9 r
7 ~' n. h' m" ^, G
' I% V& w0 O8 f8 Q1 y! j5 xВот конечный рабочий вариант квеста:
1 T+ a, G6 \& {/ B+ _0 w4 l- import sys2 @5 J0 O9 K* v8 f, ^# Y; m
- from net.sf.l2j.gameserver.model.quest import State
8 ^* q" W1 x2 G, v( E3 i4 A - from net.sf.l2j.gameserver.model.quest import QuestState+ z1 D( X- Y( @" s
- from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest$ B5 t8 {( m2 p Z/ G
% G% P2 W& N' j& ~ P- KELTIR_NPC_ID = 12082
% L% ~3 G' w( ~- i' D - FANGS_ITEM_ID = 18597 ?% q: F" Q" ^* x q+ j
- DROP_RATE = 5000004 @) R% ]0 H( g, b2 d- }
- 6 t2 M: s0 g/ L* J* d
- WORLD_MAP_ITEM_ID = 1665
& g: X( o* j: H: j( \ - ; r+ ]5 s* b9 I+ G; T
- def getCount(st) :2 n3 g% K! u2 z# j! \
- return st.getQuestItemsCount(FANGS_ITEM_ID)% O8 i; [9 I$ ^
- 8 x c; f& i: k" r
- def completed(st) :) a+ `4 q) \$ V; @1 @
- st.setState(COMPLETED)0 h. U* E& G2 v7 g
- st.clearQuestDrops()' G5 _8 @, U# b% m
- st.takeItems(FANGS_ITEM_ID,-1)
4 x$ h$ D1 ]5 [ - st.giveItems(WORLD_MAP_ITEM_ID,1)) h/ D! u0 [( L7 S) O
- st.exitQuest(False)" c: D k+ I1 x- P( a! {
- return
- q6 N) x, e; H, M5 G' [6 P1 d - 6 j ^+ n& [+ ?( F5 q+ g/ S( _8 M9 E
- def check(st) :
$ Q7 H9 u+ O" z - if getCount(st) >= 4 :2 A5 A# ?6 M& v" _9 j# i
- completed(st)
7 p4 D7 y* `2 X - return6 t0 M1 |6 f2 Y
1 z1 s7 l7 y7 J' l% R) C9 f9 b- class Quest (JQuest):
1 L0 v9 Z) k4 V a, \3 h# p; d - 9 y; G# b3 ]0 `& P$ _+ A
- def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)
1 d8 R8 v4 m( S& r+ {
' K" F6 ] s6 g/ X' i- def onEvent (self,event,st):
: J$ c3 O7 a* _) i3 S1 l - id = st.getState()- g7 h2 a5 ?) Z' Q3 J2 B
- if id == CREATED : st.setState(STARTED)& G0 P( u2 r8 E+ b) G5 K
- elif id == COMPLETED: pass& D9 v7 ^: B1 t3 f5 X% L
- elif id == STARTED : check(st)
5 u+ r, ^4 k1 \- Q; F; Y$ L - return
. J* O% m3 `+ a3 c - 2 H- L4 Y" q/ h1 z' r( a
- def onKill (self,npcId,st):; d) }5 }8 Q4 n0 W# v) S
- if npcId == KELTIR_NPC_ID:7 a+ R# c% K) u) G0 D
- n = getCount(st)% R q8 T- I( [, ~
- if n == 0:1 r! ~1 j6 u: O! I
- if st.get('chat0') == None :
+ t' v2 ^$ l4 _4 z9 O - st.set("chat0", "true")3 ?7 y! z, E/ b) P+ f4 K
- return "Chat0.htm"' I7 |2 o; W1 W1 a* \
- elif n == 1:) m# \+ g) ?3 O3 S( B! e
- if st.get('chat1') == None :
5 }: H, t7 a& U! d' ?! H; L# U - st.set("chat1", "true")& \1 }5 W/ {8 y' X
- return "Chat1.htm"
9 y6 y! ~7 a" R/ v" j& H4 N# D - elif n >= 4:) J2 |/ J; N3 K# o/ ~8 R- x6 e; y
- return "Chat4.htm"* O& k+ g+ x7 }& C( a( h, }
- return "Collect "+str(n)+" of 4 fangs"# l$ Q. f$ b, U- W- n
- return3 i& b" x7 I6 C, D5 Q* G6 G6 o6 H
' Y+ |) a3 A, D! \0 Y- QUEST = Quest(201, "Tutorial", "Tutorial quest")! F- M2 }0 ]) P
- CREATED = State('Start', QUEST)
$ ~9 T+ v" j5 q% @* G5 ] - STARTED = State('Started', QUEST)$ d1 q/ F8 ]1 q- V
- COMPLETED = State('Completed', QUEST)$ v4 ^' j, R" H# u" u2 @
1 y$ r0 r/ X j& s4 U0 L- QUEST.setInitialState(CREATED)
( d+ d T9 W* v4 u - QUEST.addStartNpc(7056)1 c: B. H5 P, u: N" s
- QUEST.addStartNpc(7012) T! k- w" p) t' P5 s8 Q$ z9 K
- QUEST.addStartNpc(7009)
3 b3 a" t3 M. x) M' ?0 n# K - QUEST.addStartNpc(7011)
5 P1 z+ ~- \( R' D% T
' V- _8 B2 B+ T" @% i- STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)6 [! f+ u3 a, L$ l
- STARTED.addKillId(KELTIR_NPC_ID)5 q, l' S. A$ a1 _
- STARTED.addTalkId(7056)
/ }* o" m' v! k" e - STARTED.addTalkI d(7012)
: k& f" K( e5 { Z% h0 k/ Z - STARTED.addTalkId(7009)
. V& x7 ~: c% ^& ]9 J - STARTED.addTalkId(7011)
Скопировать код ' V) t$ o+ F$ t) {% D
( f0 p4 [, h# o4 c4 c9 R
|