Зарегистрируйтесь сейчас чтобы найти еще больше друзей, и получить полноценный доступ ко всем функциям сайта!
Для просмотра Вам необходимо авторизоваться Если Вы еще не зарегистрированы, перейдите по ссылке:Зарегистрироваться
x
Хроники Interlude/ S' v. `* Y+ g1 Q9 R) a
Сборка L2j
* L9 B/ r9 k0 s/ }# z% ]7 q4 EОбратите внимание: в файле htm стартового NCP обязательно должна быть ссылка на квест:
! ~2 m. a, X+ A1 i- STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста:& ?' H) Y) z+ s" y! M! g0 i8 D
- { [4 P- u! r L4 t. L" \- if getCount(st) >= 4 :
! \* p1 A2 u& B, b - completed(st)
) x5 T0 N! E% E4 z6 M/ K - return
0 r ]$ ?& e( ]4 |; l - 7 S% H! }. L0 E* o! C% h
- class Quest (JQuest):
2 k4 h) s Z1 {3 }3 z" }% h5 R% M8 C - def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)0 R/ h1 D m! N* B
- def onEvent (self,event,st):( X) M1 X/ m/ v2 V. b
- id = st.getState()7 O7 ^+ B9 X( J$ Z, U
- if id == CREATED : st.setState(STARTED)
' w/ S( i9 e2 ] k8 H' B - elif id == COMPLETED: pass% j+ e+ S+ r8 R# Z1 T: y3 L2 I
- elif id == STARTED : check(st)' G0 ?, {1 m }; E8 i* O% R- \
- return9 M$ w1 [$ x! T5 w
- : m T: | V3 ^, @) z4 e
- QUEST = Quest(201,"Tutorial", "Tutorial quest")
% j/ T! z, Z* Q- l - CREATED = State('Start', QUEST)
" O' P2 ^7 C+ v( _ m' v - STARTED = State('Started', QUEST)
! R+ G% G3 I) u1 o5 h0 d1 ^ - COMPLETED = State('Completed', QUEST)
% |: O( V1 y: L
a1 g* b) ?5 W1 K I6 Y2 c6 H- QUEST.setInitialState(CREATED)
3 a+ ~3 n! D0 f) J M* A - QUEST.addStartNpc(7056)
b: C# @! X; [9 t6 W! V - STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код Теперь рассмотрим, как это работает.* }: t% j* P. u' e/ k y* T* k
Игрок подходит к начальному NCP (в данном случае 7056), нажимает на «Quest». Квест будет создан и состояние квеста перейдет к CREATED и игроку будет показана страничка Start.htm с описанием квеста. Тогда метод onEvent, поле открытия странички Start.htm переведет состояние квеста в STARTED и игроку будет показана страничка Started.htm, где будет опсание того, как найти keltirs и .т.д.7 B$ y( w" |" b
( q' f$ ~* t( F
3 ]+ T; ~8 ~3 `( g
При состоянии STARTED будет зарегистрирован дроп «fangs» при убийстве keltirs. Игрок может вернуться к стартовому NCP и спросить о квесте – метод onEvent будет вызван снова. Если у игрока не хватает необходимого количества предметов, то метод check() не переведет квест в следующее состояние и Started.htm будет показана снова. Но если игрок собрал необходимее количество предметов (в данном случае 4 клыка), то метод check() вызовет метод completed() который переведет квест в новое состояние COMPLETED, заберет все клыки, даст карту мира, т.к. это награда за квест, покажет Completed.htm и завершит квест.' W! B; a1 m6 j
# x) L+ u# f' h) `
3 ^0 [$ P$ V9 C6 W% D) }7 ^Теперь давайте сделаем наш квест более похожим на то, что он должен из себя представлять.2 u6 _" w& M$ d1 O8 Q q
Прежде всего у нас есть 3 метода для объявления их в Яве – onTalk, onKill и onEvent. Если методы onTalk и onKill не объявлены, то за них все будет делать метод onEvent, т.е. определять квестовых монстров и вызывать диалоги NCP. Есть примечание, методы onTalk и onKill будут вызывать только диалоги с NCP в зависимости от текущего состояния квеста. Метод onKill будет вызываться только тогда, когда мы убиваем квестового монстра.( B' o* Q7 I& E! Y% c' O
; _1 } L0 T3 {5 g- N- E9 Y3 b
) n' H. h' N) V q9 fДавайте рассмотрим как вызывается метод onKill при убийстве keltir в состоянии квеста STARTED:: F4 w% d4 }: j% B& T! Y' V. b
- STARTED.addKillId(KELTIR_NPC_ID)
Скопировать код и метод onKill в классе Quest:' c( Q3 v% Z2 b* l
. E0 e+ h6 _+ O. ], O- class Quest (JQuest):
/ j Y( i* |# c - ...
. R7 m/ y8 B- X5 S% ~ - def onKill (self,npcId,st):% g% Q! _ A4 [6 d" V; T1 b4 V, d
- if npcId == KELTIR_NPC_ID:
; C& y, i# {/ H4 a! Q5 t5 | - n = getCount(st)
, f( f% r, i: }" l - if n == 0:, V: ]; n; H @7 f- `
- return "Chat0.htm"' N; X" v6 T7 X7 h. ~) \
- elif n == 1:
5 a8 S4 \9 \! ~: F8 Q# U; T - return "Chat1.htm"! a# e! a( |# |' |0 w* H6 c& T
- elif n >= 4:1 S2 _( P$ u& l% |. F6 L
- return "Chat4.htm"
% A* A- w, h$ U: X: }3 c# b$ }7 x - return "Collected "+str(n)+" of 4 fangs"$ i$ D: x( j: w2 @2 @/ T
- return
Скопировать код Метод onKill (а так же метод onTalk) имеет следующие параметры:; R, j, O" X0 X" K7 N7 T
9 o: `) t/ {- b0 M/ ^4 U# n
% {, r) D, o& J( K2 e" x• self – квест
3 S4 d f w* o& ~$ x" a, D• npcId – ID NCP, которого мы должны убивать (если это метод onTalk, то ID того NCP, с которым мы должны поговорить).: H C/ b; J. u& e
• st – текущее состояние игрока.# A% H. e9 T9 ?/ [$ ?
+ M3 s1 U' i u) O9 R& z; o
. M3 q, K, s$ ?% ~, m4 c! nВ этом методе мы проверяем и отмечаем, является ли убитый NCP keltir’ом. В основном эта проверка не нужна, т.к. у нас только KELTIR_NPC_ID.( g1 t# S% v2 H! ?$ k+ W6 M
3 |% A3 `3 \7 ?- ]0 B
$ [5 R+ ]+ }4 v* D$ T6 SЗатем проверяем количество предметов (в данном случае количество клыков), и если их вообще нет, то возвращаем строку "Chat0.htm", если только один предмет, то возвращаем строку "Chat1.htm", если же предметов 4 или больше, то "Chat4.htm". Если строка возвращена из методов onEvent, onKill или onTalk, то сервер покажет соответствующие htm. В Chat0.htm может иметь следующий текст: «Вы не имеете ни одного клыка, возвращайтесь позже, когда соберете 4 штуки и бла, бла, бла…», в Chat1.htm может быть следующий текст: «У Вас всего 1 клык, по этому соберите еще…». В Chat4.htm – «Вы собрали необходимое количество предметов, возвращайтесь к вашему тренеру, что бы завершить квест…»9 o, y. v- X' F+ X0 _
: L, q/ u. c- T) B' q
9 b3 A2 Q. B) I y' H7 q$ o HПримечание: если в строка return начинается с "<html>", то будет показана страничка html с текстом, который стоит далее. Так вместо:
7 L; Z9 ?& ?) K# k$ a) ?return "Chat4.htm". C8 ?; r0 v4 ~- E( g) h+ M
) W: Z* H- u: ?8 l
- p) k2 ?8 P! a- B. c. u) O, w
можно поставить:! V2 D0 Y6 N5 k4 G: U
- return "<html><body>Return to your trainer to complete the quest</body></html>"
Скопировать код Так же если строка заканчивается без .htm или в начале нет <html>, то текст будет выведен, как системное сообщение в окне чата. В нашем случае мы сделаем так, что бы при каждом убийстве keltik выводилось системное сообщение: «Собрано N из 4-х клыков»." g6 q, E' {' b* Y7 o
) ?% k/ V1 _1 H; T
5 e7 _2 @3 ]) U' ^/ W, _Наш код для onKill имеет один недостаток. Он будет постоянно показывать Chat0.htm, Chat1.htm и Chat4.htm, нам же необходимо, что бы Chat0.htm и Chat1.htm показывались только один раз. Как нам это сделать? С помощью переменных.+ s& l1 J$ @) R k
3 h9 ?: X, q v, L3 l) a" H% g3 @- S6 U! s4 p3 T
В каждом квесте строки могут храниться с помощью переменных. Эти переменные сохраняются в Вашей БД. В каждом методе мы можем назначить, прочитать и удалить переменные. Давайте изменим метод onKill, так что бы каждый диалог вызывался только один раз.! ?& {: B9 i4 A) w& b$ f
- def onKill (self,npcId,st):
! g; y- n3 c4 k - if npcId == KELTIR_NPC_ID:
' `) I: W& p' s" W8 c, U - n = getCount(st)* i! @# B, L, S: _8 S6 J
- if n == 0:% F3 j z+ g1 v( d/ t
- if st.get('chat0') == None :
6 x4 `3 N' a2 H - st.set("chat0", "true")
1 H2 W+ C3 h+ F* C" O0 x - return "Chat0.htm"' L) {8 P: D1 Z4 F
- elif n == 1:
* j* W- J& r% Z! p" `1 J8 ~7 @4 { - if st.get('chat1') == None :; {5 q& s3 Y, Y1 E c+ g* t
- st.set("chat1", "true")
( |' T# f" M; t" ^$ m( o - return "Chat1.htm"! N" O& C H; e- o4 J0 R
- elif n >= 4:
7 X/ p- L6 p* c# J$ b2 T. w - return "Chat4.htm"
2 L6 @4 N: t$ v! L& H - return "Collected "+str(n)+" of 4 fangs"
( n, q+ |9 U) 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.# w0 b. Q' V% h8 w/ v$ r/ ~) G( h
% Y6 t1 Z8 Z7 k* B; K9 Q W d: K/ p1 y# q
Вот конечный рабочий вариант квеста:% k, j8 O$ o/ g4 g" T0 p
- import sys8 {- a% Q! B( n) j4 O
- from net.sf.l2j.gameserver.model.quest import State
& V' K3 Z! l% _ - from net.sf.l2j.gameserver.model.quest import QuestState( {7 ]2 @- U/ G1 W- d4 Y
- from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest% b5 J' t, i& f! G) D
- - o, k0 B: ], y" Y! V
- KELTIR_NPC_ID = 12082
9 ~1 I8 _/ N% S Q/ E - FANGS_ITEM_ID = 1859
, ]6 p* B, a$ n+ c2 O - DROP_RATE = 500000
6 Q/ d9 n+ i$ y% \, O9 M - [) K' L% O+ F$ p6 B
- WORLD_MAP_ITEM_ID = 16653 m& q& @ D+ R& }& d. y
- ; g9 t1 }9 |$ i8 l7 V# t9 p2 e
- def getCount(st) :
: H! y& P8 }/ M L. w9 T9 | - return st.getQuestItemsCount(FANGS_ITEM_ID)" [! L! h! k Y6 q0 p0 z, j
- ; Z5 ^0 S, n$ {4 K
- def completed(st) :# T0 u7 |$ c& [ ^$ T: Q
- st.setState(COMPLETED)
) Y0 W/ q% [% X) f5 B, O: t& [/ ` - st.clearQuestDrops()
$ t' m6 m5 Q0 {" U7 D/ ? - st.takeItems(FANGS_ITEM_ID,-1)" S) z5 b2 S. ]8 ]$ c$ j6 K+ Y
- st.giveItems(WORLD_MAP_ITEM_ID,1)) Z& W( ~$ u' b: ^/ H) E$ M! B3 a8 {3 h
- st.exitQuest(False)
$ v9 d# v. c. R9 k* {! C% f - return" n1 U8 ~; H. c* A* K, Z9 t$ N f2 o
- & H I4 {( S8 q% W9 c+ |- t
- def check(st) :
( X6 S( z: D& U; D - if getCount(st) >= 4 :; \3 P; Q9 s0 b" M$ q
- completed(st)- e% B# }6 q4 c$ v" h
- return% l: U; ]1 R( X( v$ d
* W k, h; z2 Q' G( z- class Quest (JQuest):: n1 {3 ]% u% Q1 [9 O
8 z2 b% x: B& G8 ^% K1 P- def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)* W5 Y- i% e; L4 B {. p: S4 v
, K v1 ^3 E$ E; k- def onEvent (self,event,st):! ]7 B0 e# g$ D) f. c
- id = st.getState(), u2 c) m; r1 y5 O b# O
- if id == CREATED : st.setState(STARTED)
+ G- n g- X3 [) [0 L- Y - elif id == COMPLETED: pass: x& n. ~, x0 n- G
- elif id == STARTED : check(st)! b1 `9 p4 c; h$ S
- return- C ~# g" L# Z" k( f
- . `( T' y# ~4 m( E1 K7 q
- def onKill (self,npcId,st):
9 e6 X8 y' J" _0 b9 j - if npcId == KELTIR_NPC_ID:3 p9 i# M, D {; `
- n = getCount(st)
+ O5 ?* D6 g! v/ D( t - if n == 0:& f. \* u& ^' j( h
- if st.get('chat0') == None :
5 M9 N) b* L' U- _ - st.set("chat0", "true"). d1 I: B( \7 t* E% r7 e# J
- return "Chat0.htm", x r. Z! Z$ b
- elif n == 1:4 w0 Z# v. [1 U( t2 Q
- if st.get('chat1') == None :- N( ]6 I/ B) H. v# {+ [! v! D
- st.set("chat1", "true"): N a, g% ]! }
- return "Chat1.htm"
1 v! u7 L6 y0 j - elif n >= 4:
& u9 ~4 Q& c$ f* P( D - return "Chat4.htm"
, Q" k4 C. X! F - return "Collect "+str(n)+" of 4 fangs"; b0 @; O0 z$ @1 M/ c* [0 ^3 L/ ]5 n! k0 ^
- return
/ e- {/ E7 Z' f: ] - - r$ {! O: T8 {2 j! ^
- QUEST = Quest(201, "Tutorial", "Tutorial quest"). v2 h6 t' Y0 V: M- l6 k6 |
- CREATED = State('Start', QUEST)* K2 \2 w9 u4 G5 j
- STARTED = State('Started', QUEST)/ F; X6 G. A$ J1 v3 R' R5 {
- COMPLETED = State('Completed', QUEST)
3 b3 X# l s5 @2 G - ' v/ I1 J* [9 s2 W; B# I* U
- QUEST.setInitialState(CREATED)" H' M6 B! G: N8 P7 A" F
- QUEST.addStartNpc(7056)" g- Y( O/ ]* R; y6 \
- QUEST.addStartNpc(7012)
; X* [0 t" _0 `! Q' b; X6 N - QUEST.addStartNpc(7009)
, q7 c. F0 v: Y0 { - QUEST.addStartNpc(7011)
! }8 x1 W( ~8 _- Z% l* b* y+ \
4 G+ w4 K3 {& ^; b! H- STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)5 k- F% J/ c0 U2 {
- STARTED.addKillId(KELTIR_NPC_ID)) `( r% O! ]( e5 r; q1 x. |- {) F/ t
- STARTED.addTalkId(7056)
+ D) f, [& p/ h5 r0 Y+ _ - STARTED.addTalkI d(7012)
% u! d4 L* w. V( H - STARTED.addTalkId(7009)+ m4 Z/ b, U5 t' ` v& E0 m2 {
- STARTED.addTalkId(7011)
Скопировать код 6 U3 n1 z# w5 j0 D
2 P# u2 C2 a9 G% W( x |