Название: Создаём собственные квесты (часть 2) [Версия для печати] Автор: admin Время: 2024-9-17 19:36 Название: Создаём собственные квесты (часть 2) Хроники Interlude / H1 U4 r, e% ^9 o. z; w. _) KСборка L2j 4 j a* |" G9 Z) `+ s, ^* W. G2 BОбратите внимание: в файле htm стартового NCP обязательно должна быть ссылка на квест: , c/ J5 v2 x r$ t# d; ?$ y, p
Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста:: v1 U0 [; ^) b# h5 x5 t4 j0 s: n8 l
& V) P: a4 F. t. {( p
Теперь рассмотрим, как это работает.: _, _1 Y6 F5 E; B, D5 H
Игрок подходит к начальному NCP (в данном случае 7056), нажимает на «Quest». Квест будет создан и состояние квеста перейдет к CREATED и игроку будет показана страничка Start.htm с описанием квеста. Тогда метод onEvent, поле открытия странички Start.htm переведет состояние квеста в STARTED и игроку будет показана страничка Started.htm, где будет опсание того, как найти keltirs и .т.д., p: y% n* p2 A, R
9 e- |0 \) e2 a3 B+ y
4 A7 `; n; `% ]
При состоянии STARTED будет зарегистрирован дроп «fangs» при убийстве keltirs. Игрок может вернуться к стартовому NCP и спросить о квесте – метод onEvent будет вызван снова. Если у игрока не хватает необходимого количества предметов, то метод check() не переведет квест в следующее состояние и Started.htm будет показана снова. Но если игрок собрал необходимее количество предметов (в данном случае 4 клыка), то метод check() вызовет метод completed() который переведет квест в новое состояние COMPLETED, заберет все клыки, даст карту мира, т.к. это награда за квест, покажет Completed.htm и завершит квест., b. n9 q% |+ V% `" ]7 E7 P
: H9 z# M+ f5 P6 b+ Z$ D
; M% A3 U e6 l* a( }Теперь давайте сделаем наш квест более похожим на то, что он должен из себя представлять. ' R: m5 p1 H2 n! K. bПрежде всего у нас есть 3 метода для объявления их в Яве – onTalk, onKill и onEvent. Если методы onTalk и onKill не объявлены, то за них все будет делать метод onEvent, т.е. определять квестовых монстров и вызывать диалоги NCP. Есть примечание, методы onTalk и onKill будут вызывать только диалоги с NCP в зависимости от текущего состояния квеста. Метод onKill будет вызываться только тогда, когда мы убиваем квестового монстра. * i' ~ H& P. s1 R, g j : Y- j( C" L; n6 @2 y' ^& p + ]: N$ V" h2 Y) b; {' J# E7 D8 _Давайте рассмотрим как вызывается метод onKill при убийстве keltir в состоянии квеста STARTED:5 Y- n& J1 W- E" Q# c
STARTED.addKillId(KELTIR_NPC_ID)
Скопировать код
и метод onKill в классе Quest:' r! Z% {: J+ m) K: R4 k9 @
Метод onKill (а так же метод onTalk) имеет следующие параметры: ; B" k0 q1 L( _1 k8 f6 K% a3 u; u) b5 a9 a* i3 y
o9 \5 ~; `4 c7 n• self – квест , g _6 m+ d7 Q# n. H• npcId – ID NCP, которого мы должны убивать (если это метод onTalk, то ID того NCP, с которым мы должны поговорить).8 l! c2 z, i: y
• st – текущее состояние игрока.! L" G0 h9 }: l) Q
2 c7 g- n. ~6 |6 @3 B. M, O: \" c. v" I- i
В этом методе мы проверяем и отмечаем, является ли убитый NCP keltir’ом. В основном эта проверка не нужна, т.к. у нас только KELTIR_NPC_ID." V' _9 g9 d2 \7 F2 I
1 p/ O2 V# V5 ~+ p
8 R- o3 e$ m0 s, T5 @, i# ~Затем проверяем количество предметов (в данном случае количество клыков), и если их вообще нет, то возвращаем строку "Chat0.htm", если только один предмет, то возвращаем строку "Chat1.htm", если же предметов 4 или больше, то "Chat4.htm". Если строка возвращена из методов onEvent, onKill или onTalk, то сервер покажет соответствующие htm. В Chat0.htm может иметь следующий текст: «Вы не имеете ни одного клыка, возвращайтесь позже, когда соберете 4 штуки и бла, бла, бла…», в Chat1.htm может быть следующий текст: «У Вас всего 1 клык, по этому соберите еще…». В Chat4.htm – «Вы собрали необходимое количество предметов, возвращайтесь к вашему тренеру, что бы завершить квест…»9 Q( `) r) C g
6 Z) G6 S# U3 R# I! ^) i ! U& f5 ]& E& W9 F9 j$ gПримечание: если в строка return начинается с "<html>", то будет показана страничка html с текстом, который стоит далее. Так вместо:* N, O( M; {* L% H+ ] @1 h' p$ P
return "Chat4.htm" + f- x1 F. B# _6 f + g! K5 y/ E- z. I7 T J# {7 x o4 u8 Q9 \6 \! s5 G5 j/ d
можно поставить:4 @/ X. B8 q! J, R
return "<html><body>Return to your trainer to complete the quest</body></html>"
Скопировать код
Так же если строка заканчивается без .htm или в начале нет <html>, то текст будет выведен, как системное сообщение в окне чата. В нашем случае мы сделаем так, что бы при каждом убийстве keltik выводилось системное сообщение: «Собрано N из 4-х клыков». B7 g: |( a P$ B9 j( }( c; `) y6 e# F+ ?6 p5 j4 Z1 E
U/ s; Y$ h5 h+ E
Наш код для onKill имеет один недостаток. Он будет постоянно показывать Chat0.htm, Chat1.htm и Chat4.htm, нам же необходимо, что бы Chat0.htm и Chat1.htm показывались только один раз. Как нам это сделать? С помощью переменных.2 x V7 K7 ?/ A0 S0 S! ?
% x6 q. d# U1 C( S
$ q6 C9 M7 K, g% l/ H$ k+ y
В каждом квесте строки могут храниться с помощью переменных. Эти переменные сохраняются в Вашей БД. В каждом методе мы можем назначить, прочитать и удалить переменные. Давайте изменим метод onKill, так что бы каждый диалог вызывался только один раз. . ]/ C8 |: A+ v8 W c% V
def onKill (self,npcId,st): - x) O9 }! _$ l
if npcId == KELTIR_NPC_ID: * R. d9 z; Q( o' l3 c2 D
return "Collected "+str(n)+" of 4 fangs"( j, I3 x- _5 `/ _- l& z8 h& ^ v
return
Скопировать код
Если у игрока нет клыков (n=0), то мы получаем занчение переменной 'chat0'. Когда метод onKill вызван в первый раз, то пока ни каких переменных не имеется и python возвращает значение None. В этом случае объявляется переменная и показывается диалог Chat0.htm. Когда мы убиваем keltir, но не получаем с него клык, функция st.get('chat0') возвращает строку true, а не None. И во второй раз окно с Chat0.htm не появится, но в окне чата появится строчка «Collected 0 of 4 fangs». По тому же принципу сделано и с Chat1.htm.1 x2 [1 v. D( e2 Y! d
2 k% V% H- L3 L, J! K1 t; s, b& c3 X
8 E) ~% e" O2 T* z) \3 d+ eВот конечный рабочий вариант квеста:/ s$ S; l% |/ a
import sys$ }. u! o' h7 n
from net.sf.l2j.gameserver.model.quest import State ; s! ]* ^- m: T
from net.sf.l2j.gameserver.model.quest import QuestState 0 O$ W% t2 K# S* g! U3 T: v. y
from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest $ l" g; _, c' J/ \
- ~* P4 h& }% v2 C Z4 k- C* ?
KELTIR_NPC_ID = 12082 ' ]+ l \6 D- o, s5 I
FANGS_ITEM_ID = 1859# `( m, K# {: a
DROP_RATE = 500000; d& {- L8 s' H
1 s9 t7 T3 Q% v4 j2 \" w. K- \
WORLD_MAP_ITEM_ID = 1665 : ]/ Q `& I/ |; A% ]& x
) k' f7 G4 x! H) }( z0 T/ {
def getCount(st) :: c" j2 H: Y7 p/ f9 J
return st.getQuestItemsCount(FANGS_ITEM_ID)' {3 \( H0 e8 m4 |6 }- X
* f3 s& h4 g" {4 x
def completed(st) : 5 y w3 P1 V" n* u0 T' S. {
st.setState(COMPLETED) , N( q1 \1 I$ M* S
st.clearQuestDrops()! z' z2 l/ e$ N- e; _( z
st.takeItems(FANGS_ITEM_ID,-1)7 j+ L3 l# l# V$ a+ d) s! u
st.giveItems(WORLD_MAP_ITEM_ID,1) 5 P s( L6 f0 M' l! o
st.exitQuest(False), b7 J/ E, ?$ R& a. A! I) \8 @
return8 m8 f$ ~" K7 h, b, n8 Z2 Q- S7 a
6 z5 Z# q+ E' Z9 i1 p% v" C- _3 G
def check(st) :* i( s) i8 q# |2 r5 e/ T# J
if getCount(st) >= 4 : 8 _/ I! x0 V2 H( U- j* T6 n
completed(st)8 I* @9 N# @4 W* n1 U0 F b. D
return( I! K- w F& L" y3 R3 q- N
( G8 I" V7 b: y+ r
class Quest (JQuest): ; P. E2 t' S( s$ t. W1 W7 o
8 w3 `, C2 w6 d; U+ }$ f
def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)+ C: L: U( m/ V' ?- r- |5 c) e
, Q, U7 D M$ \
def onEvent (self,event,st): * U" n" Q6 ^- c% g
id = st.getState() : d( O7 J G$ s! u
if id == CREATED : st.setState(STARTED)8 P: |1 ^+ f2 y6 Z