Название: Создаём собственные квесты (часть 2) [Версия для печати] Автор: admin Время: 2024-9-17 19:36 Название: Создаём собственные квесты (часть 2) Хроники Interlude 4 D. f. K, Y! G1 `# A% a, ZСборка L2j ]3 E. j" v9 s" EОбратите внимание: в файле htm стартового NCP обязательно должна быть ссылка на квест: - l5 e- a% L* {" x( ]* j
Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста:1 m* P1 O4 m+ s* E; Q" Z
5 P5 t: _) J4 `8 s/ \
if getCount(st) >= 4 :8 [: ~. |& N" q! P5 m% a
completed(st) 6 u' I _! p: i4 b" h
return 3 {% s, s( Z# l T+ F
7 B( O$ n& f; B* A" D: A
class Quest (JQuest): $ q' n5 b7 ~6 o3 H4 i4 {
def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr) ! r8 R ?: V& _, ~' o7 V& w. Z6 G
def onEvent (self,event,st): % h+ Q: t9 r/ i. u, {5 R% k, }
id = st.getState()% D n5 j2 w" ^8 x
if id == CREATED : st.setState(STARTED)0 D" K" N) q3 s( T
elif id == COMPLETED: pass 1 v2 i, N) p) u* P% M! @2 T
elif id == STARTED : check(st) : R) d8 q$ I$ J8 Y% [
return2 J5 X, S; ?# R& b% }
$ t7 G' k) a: c. p8 f% n! h
QUEST = Quest(201,"Tutorial", "Tutorial quest") " K0 K1 v! u$ |8 [* e& r; b) F' L
CREATED = State('Start', QUEST) $ `1 M$ J) L6 g9 C" m. P" O
STARTED = State('Started', QUEST)- p* r4 ?2 R* K0 D
Теперь рассмотрим, как это работает. / I! d8 y o5 q$ J+ JИгрок подходит к начальному NCP (в данном случае 7056), нажимает на «Quest». Квест будет создан и состояние квеста перейдет к CREATED и игроку будет показана страничка Start.htm с описанием квеста. Тогда метод onEvent, поле открытия странички Start.htm переведет состояние квеста в STARTED и игроку будет показана страничка Started.htm, где будет опсание того, как найти keltirs и .т.д.6 {$ C; a8 y" q
! X) n3 [7 U+ X6 h3 X3 o 2 Y/ p' z6 ]; o0 `При состоянии STARTED будет зарегистрирован дроп «fangs» при убийстве keltirs. Игрок может вернуться к стартовому NCP и спросить о квесте – метод onEvent будет вызван снова. Если у игрока не хватает необходимого количества предметов, то метод check() не переведет квест в следующее состояние и Started.htm будет показана снова. Но если игрок собрал необходимее количество предметов (в данном случае 4 клыка), то метод check() вызовет метод completed() который переведет квест в новое состояние COMPLETED, заберет все клыки, даст карту мира, т.к. это награда за квест, покажет Completed.htm и завершит квест.* _8 d/ n7 E! F1 z( g
. r, V3 j/ C# {0 }7 O, M5 E 5 Z' h/ J9 z- oТеперь давайте сделаем наш квест более похожим на то, что он должен из себя представлять. 6 U" o" p4 \: zПрежде всего у нас есть 3 метода для объявления их в Яве – onTalk, onKill и onEvent. Если методы onTalk и onKill не объявлены, то за них все будет делать метод onEvent, т.е. определять квестовых монстров и вызывать диалоги NCP. Есть примечание, методы onTalk и onKill будут вызывать только диалоги с NCP в зависимости от текущего состояния квеста. Метод onKill будет вызываться только тогда, когда мы убиваем квестового монстра.) z+ T' s5 r4 Q3 d: Y
+ S/ z$ v: t+ H) L% _# D8 c( H
0 i0 p' q ~) g- j$ v/ B/ S3 eДавайте рассмотрим как вызывается метод onKill при убийстве keltir в состоянии квеста STARTED:- X$ I8 W. T$ t* `5 E$ Q
STARTED.addKillId(KELTIR_NPC_ID)
Скопировать код
и метод onKill в классе Quest: ! n. V3 A# d- O 4 p! ]" }% h: ^
return "Collected "+str(n)+" of 4 fangs"% H% x8 R0 B3 D, B
return
Скопировать код
Метод onKill (а так же метод onTalk) имеет следующие параметры: ]5 F7 M t" z8 W" ~, R# X; T
6 C, X% @0 w+ B* |9 n# H
• self – квест p5 `9 J* B! \& A& E1 m• npcId – ID NCP, которого мы должны убивать (если это метод onTalk, то ID того NCP, с которым мы должны поговорить). ( [3 }' A2 J2 \• st – текущее состояние игрока.9 {3 Q0 M8 L7 w% R
) J! ^9 q6 v, u0 a, d4 w
. R8 M* r+ g- b: o& u
В этом методе мы проверяем и отмечаем, является ли убитый NCP keltir’ом. В основном эта проверка не нужна, т.к. у нас только KELTIR_NPC_ID. 0 t; L, E1 U2 `2 _ ; @ n4 {8 G% H: Z1 Y3 s* p j9 ^. ^( k
Затем проверяем количество предметов (в данном случае количество клыков), и если их вообще нет, то возвращаем строку "Chat0.htm", если только один предмет, то возвращаем строку "Chat1.htm", если же предметов 4 или больше, то "Chat4.htm". Если строка возвращена из методов onEvent, onKill или onTalk, то сервер покажет соответствующие htm. В Chat0.htm может иметь следующий текст: «Вы не имеете ни одного клыка, возвращайтесь позже, когда соберете 4 штуки и бла, бла, бла…», в Chat1.htm может быть следующий текст: «У Вас всего 1 клык, по этому соберите еще…». В Chat4.htm – «Вы собрали необходимое количество предметов, возвращайтесь к вашему тренеру, что бы завершить квест…» + U. j" @% }2 v. f, Q V( G2 p! _; K% x# K6 z* s2 W
- D) u: Y j6 M- yПримечание: если в строка return начинается с "<html>", то будет показана страничка html с текстом, который стоит далее. Так вместо:( F+ ]' m. L( b4 g3 L
return "Chat4.htm"' r. e5 t& J" L- n7 D
% {9 @; t- u9 C9 W( K; n: X) F8 ]( t. X
можно поставить: G) Y4 t% ?, ^
return "<html><body>Return to your trainer to complete the quest</body></html>"
Скопировать код
Так же если строка заканчивается без .htm или в начале нет <html>, то текст будет выведен, как системное сообщение в окне чата. В нашем случае мы сделаем так, что бы при каждом убийстве keltik выводилось системное сообщение: «Собрано N из 4-х клыков».2 w4 T! e1 u0 m& _* [
/ V" R' D4 S" g/ G: y% Q0 p3 c. T4 E% ]3 V
Наш код для onKill имеет один недостаток. Он будет постоянно показывать Chat0.htm, Chat1.htm и Chat4.htm, нам же необходимо, что бы Chat0.htm и Chat1.htm показывались только один раз. Как нам это сделать? С помощью переменных., ?5 F9 G$ R( h% \4 M
; R& E$ r( S* S/ a& t
6 K( ^- r- `8 ~8 H! W% [В каждом квесте строки могут храниться с помощью переменных. Эти переменные сохраняются в Вашей БД. В каждом методе мы можем назначить, прочитать и удалить переменные. Давайте изменим метод onKill, так что бы каждый диалог вызывался только один раз., s* y" M& z5 O5 x
Если у игрока нет клыков (n=0), то мы получаем занчение переменной 'chat0'. Когда метод onKill вызван в первый раз, то пока ни каких переменных не имеется и python возвращает значение None. В этом случае объявляется переменная и показывается диалог Chat0.htm. Когда мы убиваем keltir, но не получаем с него клык, функция st.get('chat0') возвращает строку true, а не None. И во второй раз окно с Chat0.htm не появится, но в окне чата появится строчка «Collected 0 of 4 fangs». По тому же принципу сделано и с Chat1.htm. # O- T) w1 C# n% j/ z5 _! o + l! e4 W6 {7 z$ T$ I4 y# Q; H2 W3 ]% I. }, h2 p+ ?4 ^
Вот конечный рабочий вариант квеста: ! V% {% |) M8 }8 D
import sys" g. ] ]4 [5 C# k9 w" ^0 c# f
from net.sf.l2j.gameserver.model.quest import State2 n: a! L3 b7 H, r m6 N& c$ [( Z
from net.sf.l2j.gameserver.model.quest import QuestState: V7 H. F6 T# Q/ s; [; J2 H8 |
from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest' `6 F8 {2 \ l
& b( G9 L& v3 w) P
KELTIR_NPC_ID = 120822 T, k4 h$ Q3 l% k
FANGS_ITEM_ID = 1859 # u* E8 u( n. ?/ C+ f( q t
DROP_RATE = 5000003 q V. V$ z" y" M" ^. N( e
+ a1 m P+ N( l$ K9 |& `
WORLD_MAP_ITEM_ID = 1665/ F1 C" S: e5 D% [7 T( X! g$ i
; L# _7 @$ L* Q& ^/ W: d5 o; r
def getCount(st) :4 L( G+ i' o% F: A. F0 i! J
return st.getQuestItemsCount(FANGS_ITEM_ID) 5 A4 b' W8 v% X& b) @7 }/ n
+ t7 a' w3 g, ?, N5 B
def completed(st) : % X2 }( L2 K" e1 Q
st.setState(COMPLETED)4 ], y( e* |* p/ `
st.clearQuestDrops()2 p, d" D! M$ p8 c' r: {/ |
st.takeItems(FANGS_ITEM_ID,-1) ! O' t( Y% C( \1 @# B1 G8 e