Название: Создаём собственные квесты (часть 2) [Версия для печати] Автор: admin Время: 2024-9-17 19:36 Название: Создаём собственные квесты (часть 2) Хроники Interlude1 D* M, y. O$ ^: J, {7 z Сборка L2j( J+ |. m6 h! o$ Q Обратите внимание: в файле htm стартового NCP обязательно должна быть ссылка на квест:; `1 [, r5 ^4 i5 k. j
Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста: " S% i4 N4 k! O6 I3 q- J# {; [8 w* b" X! O
if getCount(st) >= 4 : ; e" x9 g; Y3 p. U" V/ J8 m
completed(st), c% e \' C" N; l5 y
return ' v' t2 \4 p' ?
( B$ S. U: @/ t1 {& F5 _, [
class Quest (JQuest): , P: b8 U( q5 b3 K- [3 j
def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr) , L2 C. l2 M6 A' s' q* {1 C
def onEvent (self,event,st):7 x- o5 {2 Q1 c8 ]5 }
id = st.getState()5 `: q6 u. U7 `
if id == CREATED : st.setState(STARTED) / j' P; p* I( ^9 T' L
elif id == COMPLETED: pass , B: C$ `7 Q& X6 M1 ~ e
elif id == STARTED : check(st) " W; \! P, U f( z- b, k
Теперь рассмотрим, как это работает.: G3 _( \& ^: x' z
Игрок подходит к начальному NCP (в данном случае 7056), нажимает на «Quest». Квест будет создан и состояние квеста перейдет к CREATED и игроку будет показана страничка Start.htm с описанием квеста. Тогда метод onEvent, поле открытия странички Start.htm переведет состояние квеста в STARTED и игроку будет показана страничка Started.htm, где будет опсание того, как найти keltirs и .т.д.9 m. D& R5 c) P$ {
, z9 P( {3 j! i# i i% @0 O
% r% R' ~/ }) e3 wПри состоянии STARTED будет зарегистрирован дроп «fangs» при убийстве keltirs. Игрок может вернуться к стартовому NCP и спросить о квесте – метод onEvent будет вызван снова. Если у игрока не хватает необходимого количества предметов, то метод check() не переведет квест в следующее состояние и Started.htm будет показана снова. Но если игрок собрал необходимее количество предметов (в данном случае 4 клыка), то метод check() вызовет метод completed() который переведет квест в новое состояние COMPLETED, заберет все клыки, даст карту мира, т.к. это награда за квест, покажет Completed.htm и завершит квест. 7 i k2 n1 V. Y) R : M. L. @( }# q/ A, k T% ? " ^% \/ l O! B! U* T: S2 X9 @Теперь давайте сделаем наш квест более похожим на то, что он должен из себя представлять.+ |" e; _( H- `- t
Прежде всего у нас есть 3 метода для объявления их в Яве – onTalk, onKill и onEvent. Если методы onTalk и onKill не объявлены, то за них все будет делать метод onEvent, т.е. определять квестовых монстров и вызывать диалоги NCP. Есть примечание, методы onTalk и onKill будут вызывать только диалоги с NCP в зависимости от текущего состояния квеста. Метод onKill будет вызываться только тогда, когда мы убиваем квестового монстра.3 H6 ]! i% \! _3 L8 q
8 x' H7 i" b! f" N7 ^! l " a1 x; h2 E; o0 b6 DДавайте рассмотрим как вызывается метод onKill при убийстве keltir в состоянии квеста STARTED: ( D8 l& l$ Z6 E- Y: r; \
STARTED.addKillId(KELTIR_NPC_ID)
Скопировать код
и метод onKill в классе Quest:' m; ^9 f/ @8 ]
8 S- ^1 m6 r- _
class Quest (JQuest):" C1 j& Z$ }1 {+ o8 S" f% R; }9 k
return "Collected "+str(n)+" of 4 fangs"* ?, t6 e: U; ?3 q: w0 e
return
Скопировать код
Метод onKill (а так же метод onTalk) имеет следующие параметры:5 B; F! c' Y7 ~8 [6 V3 e
* d& u' }0 H- q4 z ! Z( t! O% q6 u0 H3 P3 d! b• self – квест7 }0 Y; ]5 Y. E3 ]0 u& l0 g
• npcId – ID NCP, которого мы должны убивать (если это метод onTalk, то ID того NCP, с которым мы должны поговорить). ! ]2 m# B: O+ I0 C/ \$ ]• st – текущее состояние игрока.9 l( E) @3 P' ?$ e% {) k, i& K
8 L/ L. S) P9 k* c0 h% \9 ^7 u . J! o2 b1 F0 [5 @) } NВ этом методе мы проверяем и отмечаем, является ли убитый NCP keltir’ом. В основном эта проверка не нужна, т.к. у нас только KELTIR_NPC_ID./ c0 M/ r _' T! V" s
4 x( @3 o! |3 I' I' Z9 P4 y) Z L. z
- p0 u0 k. r: Q6 @7 e9 R$ I8 g) V; C" HЗатем проверяем количество предметов (в данном случае количество клыков), и если их вообще нет, то возвращаем строку "Chat0.htm", если только один предмет, то возвращаем строку "Chat1.htm", если же предметов 4 или больше, то "Chat4.htm". Если строка возвращена из методов onEvent, onKill или onTalk, то сервер покажет соответствующие htm. В Chat0.htm может иметь следующий текст: «Вы не имеете ни одного клыка, возвращайтесь позже, когда соберете 4 штуки и бла, бла, бла…», в Chat1.htm может быть следующий текст: «У Вас всего 1 клык, по этому соберите еще…». В Chat4.htm – «Вы собрали необходимое количество предметов, возвращайтесь к вашему тренеру, что бы завершить квест…» 8 \* n- l& G. U" W+ u& h" i' d 1 @$ x: @6 e- _, ?& ? $ m( H8 V+ R0 s6 e4 JПримечание: если в строка return начинается с "<html>", то будет показана страничка html с текстом, который стоит далее. Так вместо:! Y3 j q5 e. Y5 h: W
return "Chat4.htm"* J/ `% W6 l4 i* x6 c% R3 K
7 B) p/ \# |2 S# Z( e4 S( w5 y7 i* ^ i% m7 s t0 w
можно поставить: 0 O1 k. C2 H- Y! p
return "<html><body>Return to your trainer to complete the quest</body></html>"
Скопировать код
Так же если строка заканчивается без .htm или в начале нет <html>, то текст будет выведен, как системное сообщение в окне чата. В нашем случае мы сделаем так, что бы при каждом убийстве keltik выводилось системное сообщение: «Собрано N из 4-х клыков».+ q5 J1 _$ D1 W$ ~ d! G
) r5 ^/ V2 h4 ^, f( M
% N8 K! p/ |3 s1 L7 x
Наш код для onKill имеет один недостаток. Он будет постоянно показывать Chat0.htm, Chat1.htm и Chat4.htm, нам же необходимо, что бы Chat0.htm и Chat1.htm показывались только один раз. Как нам это сделать? С помощью переменных. 4 K; d1 i t% P; u" ]% E& F# ]1 u3 c$ r- c# w% t
9 ~0 B! W1 `" s8 H
В каждом квесте строки могут храниться с помощью переменных. Эти переменные сохраняются в Вашей БД. В каждом методе мы можем назначить, прочитать и удалить переменные. Давайте изменим метод onKill, так что бы каждый диалог вызывался только один раз.- t# v$ e" T5 b/ e3 E0 ^
def onKill (self,npcId,st):. F3 E$ g9 i8 g: x
if npcId == KELTIR_NPC_ID: % q5 Q6 ~4 y2 n5 Z- X
n = getCount(st) & z# ?1 }4 c0 F! e% k4 f5 J
if n == 0: - n- d/ ?6 e7 |+ w* T
if st.get('chat0') == None :; `' j" j, K( J( I- e
st.set("chat0", "true")1 d3 ^' F' A J5 j( I; @& y! }) N
return "Chat0.htm" ! y8 A. Z1 } d: a
elif n == 1: ; `7 F! \" y/ U- ~3 p
if st.get('chat1') == None : 0 i0 y7 }6 c+ x' b6 H# K6 A
return "Chat4.htm"$ n: j/ x' \7 k5 T( @9 t( s. s( V
return "Collected "+str(n)+" of 4 fangs" / P& U! E" W* \5 Y3 d# q# k
return
Скопировать код
Если у игрока нет клыков (n=0), то мы получаем занчение переменной 'chat0'. Когда метод onKill вызван в первый раз, то пока ни каких переменных не имеется и python возвращает значение None. В этом случае объявляется переменная и показывается диалог Chat0.htm. Когда мы убиваем keltir, но не получаем с него клык, функция st.get('chat0') возвращает строку true, а не None. И во второй раз окно с Chat0.htm не появится, но в окне чата появится строчка «Collected 0 of 4 fangs». По тому же принципу сделано и с Chat1.htm. , r, C& y) W7 ]( ]7 r; r! d' Y# @' X! ~! V. C; w% Y9 b) H/ S; N5 Z
: z+ l; \; C6 f& k- Z. _Вот конечный рабочий вариант квеста:5 s3 v. q7 J7 V& \
import sys , U6 [* e7 l+ S- ?1 ]
from net.sf.l2j.gameserver.model.quest import State % f3 {, f& p9 A
from net.sf.l2j.gameserver.model.quest import QuestState : t; `: K" N2 `5 t G9 j. }! B
from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest 4 s3 [7 z+ _+ |9 N" I8 d
( N/ L4 s; A8 R
KELTIR_NPC_ID = 12082 ! E# ], H( |% F
FANGS_ITEM_ID = 1859% ~9 j! P7 s# A6 @" r0 }2 W
DROP_RATE = 500000 7 T9 G; H. \- N$ ^
- c$ X7 J! r* N5 Y i7 w4 X
WORLD_MAP_ITEM_ID = 1665 . y1 r+ Q% v% h' Z; _$ |
$ Z1 N q- i1 s! w( z# w% \
def getCount(st) :. ?% i; U+ i# ^7 J4 j
return st.getQuestItemsCount(FANGS_ITEM_ID)% ]# ^: b* V% K. T. f