Зарегистрируйтесь сейчас чтобы найти еще больше друзей, и получить полноценный доступ ко всем функциям сайта!
Для просмотра Вам необходимо авторизоваться Если Вы еще не зарегистрированы, перейдите по ссылке:Зарегистрироваться
x
Хроники Interlude% h+ U0 l+ j' e& R: ]. ?( e7 U
Сборка L2j$ r* H7 a6 C7 W: g5 I1 T
Обратите внимание: в файле htm стартового NCP обязательно должна быть ссылка на квест:
3 v) X3 `# l3 B- STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста:$ x& v& N. y7 G; R3 L' Y- \
$ G5 Y7 ^* [9 v# `5 i2 D+ P- if getCount(st) >= 4 :9 t3 Q( y' y: x3 r" v2 D1 b y! T
- completed(st)
% G; X; `( a c" W - return
4 ~ o4 G/ k) N% o% ]1 ~0 C
6 T8 Y7 l5 @3 o2 A5 F' a3 c- class Quest (JQuest):
4 Q9 E( Y# ^2 |! I - def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)
: ^: `6 F& K* o' H M - def onEvent (self,event,st):
, r* I/ q6 U @$ ~+ Z( j; Y - id = st.getState()
0 ]; x3 `1 j0 L" e, I$ e L7 M$ w - if id == CREATED : st.setState(STARTED)
4 ^6 E# ?* c$ d7 U. h3 }7 H - elif id == COMPLETED: pass# \6 S9 d# n, p# u# P* [, `
- elif id == STARTED : check(st)
; y/ {) {+ D- n+ H8 k( E% W8 j9 G1 N - return
1 \# ]6 U6 m/ u% q5 `
2 `" ?, H [- Z- p- QUEST = Quest(201,"Tutorial", "Tutorial quest")$ N% l$ i" p3 G, N7 w
- CREATED = State('Start', QUEST)
# V2 P2 ?, V! W- V4 c - STARTED = State('Started', QUEST)
+ ?, {$ O. t% B; G% y4 I - COMPLETED = State('Completed', QUEST)
3 X. v; I1 O( I& \
, l3 U; O3 a3 o! ^4 _; K6 P# {- QUEST.setInitialState(CREATED)$ a: d* V, X/ }/ U( r& d8 r$ ~8 J
- QUEST.addStartNpc(7056)
5 R Y9 ]! O/ e J' X: Q) B4 Q7 h$ S - STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код Теперь рассмотрим, как это работает.
& Z' C" b9 [* d: f& X* x2 nИгрок подходит к начальному NCP (в данном случае 7056), нажимает на «Quest». Квест будет создан и состояние квеста перейдет к CREATED и игроку будет показана страничка Start.htm с описанием квеста. Тогда метод onEvent, поле открытия странички Start.htm переведет состояние квеста в STARTED и игроку будет показана страничка Started.htm, где будет опсание того, как найти keltirs и .т.д.3 [) K, p- O2 z
9 v6 @5 J* I3 x" C( v d6 o/ w) ~$ v+ ?; N. s3 Q/ G0 w8 W+ ~, q! h# x
При состоянии STARTED будет зарегистрирован дроп «fangs» при убийстве keltirs. Игрок может вернуться к стартовому NCP и спросить о квесте – метод onEvent будет вызван снова. Если у игрока не хватает необходимого количества предметов, то метод check() не переведет квест в следующее состояние и Started.htm будет показана снова. Но если игрок собрал необходимее количество предметов (в данном случае 4 клыка), то метод check() вызовет метод completed() который переведет квест в новое состояние COMPLETED, заберет все клыки, даст карту мира, т.к. это награда за квест, покажет Completed.htm и завершит квест.
l) o' B: u! {4 m2 L5 y# m
9 ~3 f, ?4 u! C7 d2 @8 \
5 g: y$ j3 W( C2 ]+ KТеперь давайте сделаем наш квест более похожим на то, что он должен из себя представлять.% B# e6 b0 D! ^& f# \
Прежде всего у нас есть 3 метода для объявления их в Яве – onTalk, onKill и onEvent. Если методы onTalk и onKill не объявлены, то за них все будет делать метод onEvent, т.е. определять квестовых монстров и вызывать диалоги NCP. Есть примечание, методы onTalk и onKill будут вызывать только диалоги с NCP в зависимости от текущего состояния квеста. Метод onKill будет вызываться только тогда, когда мы убиваем квестового монстра.. ~* o% {) e1 W! W: G$ R& y/ b/ C+ w: Y
5 Q, G& f, K) i8 n7 _/ p/ D" ^/ I, w4 r; [$ z q8 n& H1 L/ v
Давайте рассмотрим как вызывается метод onKill при убийстве keltir в состоянии квеста STARTED:9 Z, A. K6 S _# X i
- STARTED.addKillId(KELTIR_NPC_ID)
Скопировать код и метод onKill в классе Quest:8 O/ a- y; `( R% L$ r
: W5 R( s. [7 O. z1 o- k" X- class Quest (JQuest):; c% e1 F5 u |" Y3 H- Y5 `
- ...$ Y# L4 [& b8 z" A
- def onKill (self,npcId,st):
7 [3 X- u- S2 O- {8 X - if npcId == KELTIR_NPC_ID:/ v9 I6 y- _; }0 h- M9 k
- n = getCount(st)3 i. ]) G0 q9 ^+ [; a7 |
- if n == 0:* y/ F( |* l7 F
- return "Chat0.htm"- F& }3 ?- ]" G' o) L4 a) G$ L
- elif n == 1:
* Y9 f4 \& b* K - return "Chat1.htm"
% |* W& `" W8 k7 F& h e& b) f - elif n >= 4:3 n) I# V7 ?" }( C% ]( \, M
- return "Chat4.htm"
, J, K5 y" x; W& A& B/ g' L - return "Collected "+str(n)+" of 4 fangs"8 [/ J; l' C6 W; i5 x7 h1 c9 R
- return
Скопировать код Метод onKill (а так же метод onTalk) имеет следующие параметры:) P8 g; h$ `1 j$ d- r4 }
8 i' u( q9 Y# N( F1 E) Z1 |/ S/ o
• self – квест, d- A: o6 @0 h8 J, t! G, b
• npcId – ID NCP, которого мы должны убивать (если это метод onTalk, то ID того NCP, с которым мы должны поговорить).0 A+ m x8 r9 h9 J
• st – текущее состояние игрока.7 W, Z. `. c3 Z1 }/ h* J5 w/ E
0 F( v9 f8 P3 s1 I# ^3 J
0 }1 I) F3 |1 yВ этом методе мы проверяем и отмечаем, является ли убитый NCP keltir’ом. В основном эта проверка не нужна, т.к. у нас только KELTIR_NPC_ID." K7 @; I4 d, c q6 h
" y4 ^1 d: C; T3 b( o7 E
0 L' g6 s/ [, hЗатем проверяем количество предметов (в данном случае количество клыков), и если их вообще нет, то возвращаем строку "Chat0.htm", если только один предмет, то возвращаем строку "Chat1.htm", если же предметов 4 или больше, то "Chat4.htm". Если строка возвращена из методов onEvent, onKill или onTalk, то сервер покажет соответствующие htm. В Chat0.htm может иметь следующий текст: «Вы не имеете ни одного клыка, возвращайтесь позже, когда соберете 4 штуки и бла, бла, бла…», в Chat1.htm может быть следующий текст: «У Вас всего 1 клык, по этому соберите еще…». В Chat4.htm – «Вы собрали необходимое количество предметов, возвращайтесь к вашему тренеру, что бы завершить квест…»0 _6 g9 d, [8 [- p
* {- r: F! Q' ?+ c7 J! X7 w
) u/ Y+ V# k9 G" r R, kПримечание: если в строка return начинается с "<html>", то будет показана страничка html с текстом, который стоит далее. Так вместо:7 Q: N% m# G( U
return "Chat4.htm"$ T* }9 @# c5 m. U
* b5 K- u& d. ~: _% u5 S- t
6 u" ^3 R( j3 V8 Y$ Iможно поставить:/ A5 i; Q0 i$ G8 I# e
- return "<html><body>Return to your trainer to complete the quest</body></html>"
Скопировать код Так же если строка заканчивается без .htm или в начале нет <html>, то текст будет выведен, как системное сообщение в окне чата. В нашем случае мы сделаем так, что бы при каждом убийстве keltik выводилось системное сообщение: «Собрано N из 4-х клыков».
7 |& t) [2 i; {0 M. a% F9 |8 E
- h# h; i8 ?8 |4 V! S$ t; t7 v. V! c6 d$ s
Наш код для onKill имеет один недостаток. Он будет постоянно показывать Chat0.htm, Chat1.htm и Chat4.htm, нам же необходимо, что бы Chat0.htm и Chat1.htm показывались только один раз. Как нам это сделать? С помощью переменных.
( c0 a) Y6 f% o! e
/ Y( V$ \) r8 |& p$ |% M
, P' R# a, C; V7 GВ каждом квесте строки могут храниться с помощью переменных. Эти переменные сохраняются в Вашей БД. В каждом методе мы можем назначить, прочитать и удалить переменные. Давайте изменим метод onKill, так что бы каждый диалог вызывался только один раз.
0 D: G- q6 V8 G8 ?% K" S1 n$ b- def onKill (self,npcId,st): z0 f; B9 K F: m) p$ i: D5 N
- if npcId == KELTIR_NPC_ID:
1 H3 a0 a# x) Z# `6 ]- Y) v: f H - n = getCount(st)" B+ @3 R5 X8 d8 q
- if n == 0:
2 M+ v# x" q: l$ w% n8 I( o3 F% C - if st.get('chat0') == None :
0 b. f. v8 H2 @6 M - st.set("chat0", "true")
- N# I6 W! J4 \7 u# _ - return "Chat0.htm"3 O; I0 X% a/ Z5 X
- elif n == 1:* Y. o# t4 g! [: @
- if st.get('chat1') == None :
7 m, H2 Y* g" u6 h/ d3 U- u - st.set("chat1", "true"). `9 r0 T& L0 x( F: X
- return "Chat1.htm"
6 y7 d; ~: a5 y0 ~: N; x - elif n >= 4:* _' Y c9 s3 c2 c" @& } R
- return "Chat4.htm"! O3 q& L/ \) @# u- \
- return "Collected "+str(n)+" of 4 fangs"
2 A2 W" M& d' N" N- J* ^; N - return
Скопировать код Если у игрока нет клыков (n=0), то мы получаем занчение переменной 'chat0'. Когда метод onKill вызван в первый раз, то пока ни каких переменных не имеется и python возвращает значение None. В этом случае объявляется переменная и показывается диалог Chat0.htm. Когда мы убиваем keltir, но не получаем с него клык, функция st.get('chat0') возвращает строку true, а не None. И во второй раз окно с Chat0.htm не появится, но в окне чата появится строчка «Collected 0 of 4 fangs». По тому же принципу сделано и с Chat1.htm.
$ y. x2 [% a% p4 V/ i# \1 A# U6 h& Y8 O, p1 {6 \2 E
1 W6 R! T% }0 m
Вот конечный рабочий вариант квеста:% h% w" I0 v6 Z6 n9 b7 N, S
- import sys$ w( C ~' f+ x- r
- from net.sf.l2j.gameserver.model.quest import State
" F: `6 y! L5 J5 c& Y# x - from net.sf.l2j.gameserver.model.quest import QuestState
- q+ w' `1 p5 S - from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest
/ a G* R% Z$ A8 W3 @0 t/ ^
T# N) _5 p: r% H- `1 S7 F2 u+ W$ E- KELTIR_NPC_ID = 12082
* R6 h; P: i: o" k - FANGS_ITEM_ID = 1859! u2 p; _6 P, N& C! J, d7 q
- DROP_RATE = 500000; P2 I2 s) t8 Z& H
: g4 p Z4 Y0 G# s1 {5 z4 F- WORLD_MAP_ITEM_ID = 1665
4 @/ G# ], b/ j' Y ]# ?
' S! Y0 D; K) c6 |6 Q& @+ }1 a- def getCount(st) :5 S/ {5 S, Y" ~9 h% x6 Q: N7 a
- return st.getQuestItemsCount(FANGS_ITEM_ID)
% Z7 D. x' P6 d& M" C/ c2 H - 9 h6 E/ m7 `/ Z
- def completed(st) :8 e" Y" V/ [7 W! X. @; N/ f9 i6 ?
- st.setState(COMPLETED)/ d9 C) D0 [% j. y" T/ p& Y
- st.clearQuestDrops()5 @/ c N% ~7 }8 N* @) v5 u2 g
- st.takeItems(FANGS_ITEM_ID,-1)( _# z8 N S6 i2 W
- st.giveItems(WORLD_MAP_ITEM_ID,1)( N/ D' l8 M) |- D. M3 L
- st.exitQuest(False)
# _6 ?, S7 N% o q - return
f; h" w: S4 N5 Y2 A! |/ r
* I3 w/ v$ V. ]" V- def check(st) :
0 s Q d3 y- ~( E& V# |3 E - if getCount(st) >= 4 :
. x0 ~9 C$ r. o; B3 E7 D7 x - completed(st)
, Q- @( b) m) D& L: c2 U" m7 a - return
1 ~( r6 w3 r0 ~1 V) _0 a) A- T
C2 `$ L1 L4 d1 D2 P6 k- class Quest (JQuest):
- {0 O, V) u! g+ C' Z: a6 S; b* } - J# N) q* K& Q& }% n; ^
- def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)3 \4 P' p; \/ Q i9 [+ f K( ?' X
( j' Z. ?# g, v: C- def onEvent (self,event,st):
* h# w: i6 V3 I0 C4 g; Z) C8 O - id = st.getState()
% p! f/ Z6 j9 y. ~ - if id == CREATED : st.setState(STARTED)# x' Z" N! B# K- a2 \ D+ E7 ~3 s+ B
- elif id == COMPLETED: pass
) a& u% d1 { f L+ C, A - elif id == STARTED : check(st)
' v+ G( ^+ Z& u! g" j - return+ N1 Y; Q& U+ D/ B" C2 Q0 w5 i
& f6 S. I3 c& ~$ t" N! Z- def onKill (self,npcId,st):
& F4 M3 h( O1 c( c - if npcId == KELTIR_NPC_ID:
- R8 `. B* U/ G8 A8 F7 b/ N - n = getCount(st)
; d* H( n6 z+ W3 ~6 J/ C - if n == 0:
M: ^2 Z8 \$ ?$ @9 Q3 V4 { - if st.get('chat0') == None :
$ G9 E( p# g- y) _7 U; c- d/ Q - st.set("chat0", "true") ]3 E: S: |, D
- return "Chat0.htm"# `. p/ {) ~3 r( H8 w) `
- elif n == 1:
7 i0 x: {. r$ ?) X) H3 ~; Y5 m$ k - if st.get('chat1') == None :6 k0 A# ^6 X8 B5 }$ U6 B0 I: R' |
- st.set("chat1", "true")
- w9 B' S2 ?7 k( H" }; P - return "Chat1.htm"
/ K2 i' o2 o7 k: h* _ - elif n >= 4:) r# Q2 m* A/ G+ T* T7 k Y9 y0 X
- return "Chat4.htm") Y: P1 d' C1 r9 j
- return "Collect "+str(n)+" of 4 fangs"
]* V$ y! q. k! ^ - return
- A1 S9 S' G! d - % v, C3 B/ z6 I: r% i! q) o: H6 e
- QUEST = Quest(201, "Tutorial", "Tutorial quest")
7 A2 [( k4 x- x) W2 }% E) F - CREATED = State('Start', QUEST)
% g; U( t) j* S. i - STARTED = State('Started', QUEST)
9 Z k; l4 Z: |, k. k - COMPLETED = State('Completed', QUEST) P q9 Q7 I0 W, r
- ) _ E6 }1 A4 l
- QUEST.setInitialState(CREATED)7 a1 P* b e( y |2 j: _! x* ~# |
- QUEST.addStartNpc(7056)
! M- k l v5 i5 b9 S - QUEST.addStartNpc(7012)4 T" N, t5 d/ x5 f
- QUEST.addStartNpc(7009)' g& p- |- v1 g- ^! c
- QUEST.addStartNpc(7011)
: s& U. q, W# S+ X - ' D# s) a9 T% R, k; J" _ `
- STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)) Y! @+ [9 a2 C$ [ l
- STARTED.addKillId(KELTIR_NPC_ID)3 g' h* V. Y9 g0 H3 I- A
- STARTED.addTalkId(7056)
6 T. p: X1 j6 k: P1 W4 W - STARTED.addTalkI d(7012)
8 m5 r* F+ K3 r% _$ P; L3 L - STARTED.addTalkId(7009)% r) [* \* \2 b+ H1 L
- STARTED.addTalkId(7011)
Скопировать код
* ?: n% u/ O! r j! V5 j& @
/ a" o8 ^# j& Q! H9 Z' ~, H1 b |