artace.ru - творческий сектор

Название: Создаём собственные квесты (часть 2) [Версия для печати]

Автор: admin    Время: 2024-9-17 19:36
Название: Создаём собственные квесты (часть 2)
Хроники        Interlude" L" G# D: L2 M( G. y
Сборка        L2j( e5 j) l( e6 S1 C% F+ G: V& D' [
Обратите внимание: в файле htm стартового NCP обязательно должна быть ссылка на квест:
( g4 ?9 g+ F; s
  1. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста:5 o  j4 B! @5 A( L, ?  o6 d* l3 M

7 S' f% S5 X- K" l# u
  1. if getCount(st) >= 4 :0 w  Q, N9 m1 W2 _5 q& ~; K
  2. completed(st)
    3 P" i: z6 D5 a6 r" a( p
  3.   return( N% @* D6 r, f/ `7 i9 ?; e
  4. 6 U) b+ G3 t4 ?% J, H
  5. class Quest (JQuest):
    : K% C7 N2 h. f0 f7 K9 `
  6.   def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr): L9 [* T7 I4 M3 T( z* O% M
  7.   def onEvent (self,event,st):+ Y% h8 S9 y7 l
  8. id = st.getState()  g$ M+ }. @9 H  f4 `, S% N) i
  9. if   id == CREATED  : st.setState(STARTED)) T$ ~0 a* m4 W3 U. q- W
  10. elif id == COMPLETED: pass* P. j2 f2 K) W$ z9 V" ^1 k' r9 F
  11. elif id == STARTED  : check(st)3 h* b$ R& @4 S& ?$ U
  12. return6 c4 M( P; ]- M5 A7 P. d! C2 G+ Z) j
  13. + E! b; b0 m' z$ S  c; Q' t
  14. QUEST     = Quest(201,"Tutorial", "Tutorial quest")
    7 y+ U7 v: G; F* N$ l# b4 p- b
  15. CREATED   = State('Start',     QUEST)
    2 T) m* z. Z7 k( f" ^' ?, K
  16. STARTED   = State('Started',   QUEST); x9 d- W; \3 x  \5 I" H8 k" ?& x
  17. COMPLETED = State('Completed', QUEST)
    9 Z" j& `- `& I0 X1 L; ]
  18. * ?; q, \0 u0 U1 ]# p+ J
  19. QUEST.setInitialState(CREATED)
    9 v7 u% n9 Z! ?& k
  20. QUEST.addStartNpc(7056)5 h) y$ h# ?; I. L1 O0 R2 [
  21. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Теперь рассмотрим, как это работает.9 x1 l# F; o0 A
Игрок подходит к начальному NCP (в данном случае 7056), нажимает на «Quest». Квест будет создан и состояние квеста перейдет к CREATED и игроку будет показана страничка Start.htm с описанием квеста. Тогда метод onEvent, поле открытия странички Start.htm переведет состояние квеста в STARTED и игроку будет показана страничка Started.htm, где будет опсание того, как найти keltirs и .т.д.
/ X! L, M  _; v/ A/ {* u, t: M* E; ]* C) ]2 v( D( V& O
& I: \7 g2 e/ e
При состоянии STARTED будет зарегистрирован дроп «fangs» при убийстве keltirs. Игрок может вернуться к стартовому NCP и спросить о квесте – метод onEvent будет вызван снова. Если у игрока не хватает необходимого количества предметов, то метод check() не переведет квест в следующее состояние и Started.htm будет показана снова. Но если игрок собрал необходимее количество предметов (в данном случае 4 клыка), то метод check() вызовет метод completed() который переведет квест в новое состояние COMPLETED, заберет все клыки, даст карту мира, т.к. это награда за квест, покажет Completed.htm и завершит квест.
. w6 {: O% ?3 t# A. m. V. L& Y* q0 h
: A; p9 n5 @2 M  K
Теперь давайте сделаем наш квест более похожим на то, что он должен из себя представлять.
8 r9 @4 e% {1 m- i7 Q- NПрежде всего у нас есть 3 метода для объявления их в Яве – onTalk, onKill и onEvent. Если методы onTalk и onKill не объявлены, то за них все будет делать метод onEvent, т.е. определять квестовых монстров и вызывать диалоги NCP. Есть примечание, методы onTalk и onKill будут вызывать только диалоги с NCP в зависимости от текущего состояния квеста. Метод onKill будет вызываться только тогда, когда мы убиваем квестового монстра.
- B0 Z* p- p; {4 U4 H5 `5 D5 @4 ~: m+ y+ G* q5 q0 q' _+ X7 s

4 T8 l' K$ ~! SДавайте рассмотрим как вызывается метод onKill при убийстве keltir в состоянии квеста STARTED:: [3 e3 \$ |) f  u/ R/ F) ~9 n/ `5 x
  1. STARTED.addKillId(KELTIR_NPC_ID)
Скопировать код
и метод onKill в классе Quest:4 H$ x" D1 I! W  d& C

4 F4 x8 k1 o- e; C- }" s- K7 Z
  1. class Quest (JQuest):$ z7 o$ W9 I/ j' a4 x; N' h  j
  2.   ...3 X5 g1 H! V; c# G2 W% N4 N
  3.   def onKill (self,npcId,st):
    # B) @. n! G0 ~
  4. if npcId == KELTIR_NPC_ID:) B  V7 }! `" C4 C# |+ W
  5.    n = getCount(st)
    / M% l: d* m9 _; x& R/ [7 J
  6.    if   n == 0:7 ~1 |8 W2 d" F* M& w
  7.        return "Chat0.htm"- [+ L/ V! v. M/ Q( J( g7 e
  8.    elif n == 1:
    " B, ~/ d0 c8 |% H$ }
  9.        return "Chat1.htm"
    6 i* i2 e& E" `3 N  ?; X
  10.    elif n >= 4:7 d# R5 b7 o$ D2 q3 t/ g" t' w2 v
  11.        return "Chat4.htm"* Z& T$ W- S3 D/ _% A+ T- e; b
  12.    return "Collected "+str(n)+" of 4 fangs"
    3 X3 J7 A- h4 P0 S2 {( l( O% U
  13. return
Скопировать код
Метод onKill (а так же метод onTalk) имеет следующие параметры:
- V9 ^# R2 |1 H9 ^
9 p! X, f. I6 ]2 a3 x1 j

; V  I/ O6 C, D3 c4 y• self – квест
* _9 U7 Y9 `; K- w! D• npcId – ID NCP, которого мы должны убивать (если это метод onTalk, то ID того NCP, с которым мы должны поговорить).! ~5 r6 R3 r0 G: \% J
• st – текущее состояние игрока.& ^$ ~. i( K5 x0 P9 W) y

6 f/ d. T  l1 t' F& K  K- J5 Y3 U

' Z9 Q! x- u: M: g. i4 b# RВ этом методе мы проверяем и отмечаем, является ли убитый NCP keltir’ом. В основном эта проверка не нужна, т.к. у нас только KELTIR_NPC_ID.# p( J" U6 Y: P5 x3 L" D

7 F$ i+ i% ~; I

- l" B5 [; f: K. {' Y- m/ DЗатем проверяем количество предметов (в данном случае количество клыков), и если их вообще нет, то возвращаем строку "Chat0.htm", если только один предмет, то возвращаем строку "Chat1.htm", если же предметов 4 или больше, то "Chat4.htm". Если строка возвращена из методов onEvent, onKill или onTalk, то сервер покажет соответствующие htm. В Chat0.htm может иметь следующий текст: «Вы не имеете ни одного клыка, возвращайтесь позже, когда соберете 4 штуки и бла, бла, бла…», в Chat1.htm может быть следующий текст: «У Вас всего 1 клык, по этому соберите еще…». В Chat4.htm – «Вы собрали необходимое количество предметов, возвращайтесь к вашему тренеру, что бы завершить квест…»0 a; P# K  K# v- S3 S+ j: L. T; w" s
; v$ L8 K9 d) n" z- W: g! x) E
2 N* c. T, H6 s( N; \* N
Примечание: если в строка return начинается с "<html>", то будет показана страничка html с текстом, который стоит далее. Так вместо:
- h) b1 d- [% D/ T9 R! \2 {return "Chat4.htm"" R# Y8 h/ u7 w

/ E2 W  Q+ E7 A4 S3 u

5 O/ ~  X! M+ {! q. a+ q; Gможно поставить:
3 e+ z+ ~- W1 L7 o1 ~0 ?
  1. return "<html><body>Return to your trainer to complete the quest</body></html>"
Скопировать код
Так же если строка заканчивается без .htm или в начале нет <html>, то текст будет выведен, как системное сообщение в окне чата. В нашем случае мы сделаем так, что бы при каждом убийстве keltik выводилось системное сообщение: «Собрано N из 4-х клыков».8 l8 q" |% l  F. y; m2 ~( g! C$ i4 Q4 z
$ Y0 t) E# @- Q( u7 X8 O
9 q  `% o  {  d/ A7 O: }8 n
Наш код для onKill имеет один недостаток. Он будет постоянно показывать Chat0.htm, Chat1.htm и Chat4.htm, нам же необходимо, что бы Chat0.htm и Chat1.htm показывались только один раз. Как нам это сделать? С помощью переменных.
5 M1 u8 d/ w: v9 i. _/ @) w* t

( j8 p1 q5 y6 t; A8 eВ каждом квесте строки могут храниться с помощью переменных. Эти переменные сохраняются в Вашей БД. В каждом методе мы можем назначить, прочитать и удалить переменные. Давайте изменим метод onKill, так что бы каждый диалог вызывался только один раз.3 |4 Q: U$ s  X1 ^9 U& N
  1. def onKill (self,npcId,st):
    # w8 P0 X9 M& s6 ?
  2. if npcId == KELTIR_NPC_ID:; p& L! ^1 A. A8 f) I
  3. n = getCount(st)! g- o- _; T, p0 ~9 {0 ^8 x9 a
  4. if n == 0:
    ( ?, g6 @; i6 y7 b' C
  5. if st.get('chat0') == None :
    , F6 ]4 n& U8 ?8 i  C2 O) W
  6. st.set("chat0", "true")
    4 `) }5 Z+ s3 n8 L; G2 _" x, g8 S
  7. return "Chat0.htm". V* E' `& u+ M+ r
  8. elif n == 1:6 p! K: ^/ A1 Z+ A8 L, K
  9. if st.get('chat1') == None :
    2 ~) ^  s6 x2 r, Z% R6 L
  10. st.set("chat1", "true")
    9 l9 i8 Q/ y& D& P  B. Q* h
  11. return "Chat1.htm": n4 @, E4 S) W/ Q% I5 E# a0 j' H
  12. elif n >= 4:' s) L& [2 Z6 |, M" e
  13. return "Chat4.htm"
    4 f, e  I" D; p
  14. return "Collected "+str(n)+" of 4 fangs"! L& k8 s: _$ b# s2 p
  15. return
Скопировать код
Если у игрока нет клыков (n=0), то мы получаем занчение переменной 'chat0'. Когда метод onKill вызван в первый раз, то пока ни каких переменных не имеется и python возвращает значение None. В этом случае объявляется переменная и показывается диалог Chat0.htm. Когда мы убиваем keltir, но не получаем с него клык, функция st.get('chat0') возвращает строку true, а не None. И во второй раз окно с Chat0.htm не появится, но в окне чата появится строчка «Collected 0 of 4 fangs». По тому же принципу сделано и с Chat1.htm.
- z9 V% Y( T4 D" Z- U
& m$ c& l6 E6 ^; O0 M( z' c

. }% U( c/ \) A, mВот конечный рабочий вариант квеста:
" D& ^0 d5 t0 J4 V3 n% D
  1. import sys
    1 f- Y1 A0 u. M: j
  2. from net.sf.l2j.gameserver.model.quest import State
    0 b0 g, e. a% n- l+ o6 ^
  3. from net.sf.l2j.gameserver.model.quest import QuestState. E$ @$ i0 B* d: L" F! B
  4. from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest
    * k* U1 c4 c) h( s% P9 U3 \
  5. 5 v& s. C  ^( A4 p4 {% Q
  6. KELTIR_NPC_ID = 12082
    * E( e, @2 x$ y" Y
  7. FANGS_ITEM_ID = 1859
    ; {; v5 M. Q3 W. {7 n, |
  8. DROP_RATE    = 500000( m, U5 h/ X- s0 t
  9. $ P* `% ?/ s9 v. f) N5 R: l3 C' a
  10. WORLD_MAP_ITEM_ID = 16653 G' b$ a! u$ p7 @; Y% ]/ H* H: K* z% F0 {

  11. 9 r. f+ U! l/ o5 l+ `, n
  12. def getCount(st) :
    5 U+ ^& U* }2 x# H
  13. return st.getQuestItemsCount(FANGS_ITEM_ID)
    9 R0 V; R8 J8 I' }

  14. $ H. ]! _! `$ P
  15. def completed(st) :, T- s6 t) F/ b' q$ B& T
  16. st.setState(COMPLETED)& J  e, @/ V- Q1 S  P9 E2 }  V
  17. st.clearQuestDrops()
    3 ^% A9 O# T) j- k: g$ I
  18. st.takeItems(FANGS_ITEM_ID,-1)  F1 \# d( G9 ]) [
  19. st.giveItems(WORLD_MAP_ITEM_ID,1). p/ o5 i1 L4 b; r& v; j! F
  20. st.exitQuest(False)) D( ]+ o9 V4 a8 m6 a4 @
  21. return
    6 Y4 j& y; F. k, p, G
  22. # B, ^: @4 x- g6 R5 E4 @5 @& k
  23. def check(st) :9 G2 U  K; `6 b& t3 \
  24. if getCount(st) >= 4 :
    9 {% s* B% d, g/ B6 k2 T4 d
  25. completed(st), y! p2 F# c% A" u
  26. return
    , g6 M2 T; A7 L

  27. / q, N1 x" Z0 ?3 z5 U$ X! V
  28. class Quest (JQuest):
    / ]6 Y4 H! Q5 s- ?+ M2 t

  29. * z5 S. X4 y+ E% `4 x: n
  30. def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)
    4 c" v2 f; A( P* Y; ?# G
  31. 7 u: F  v( A, K. @! Y
  32. def onEvent (self,event,st):/ r9 m2 y0 a; d, M7 s
  33. id = st.getState()
    ( H8 w5 H0 I0 g0 q0 A
  34. if id == CREATED : st.setState(STARTED)* Y& Q! K0 L2 q$ B( W+ g
  35. elif id == COMPLETED: pass4 R$ d  U! |& G& R9 i2 r* @  P! d
  36. elif id == STARTED : check(st)
    4 ?8 q. H! g' b, \+ J$ d
  37. return, V1 b$ \1 w6 |8 K1 [
  38. 0 @7 f5 |6 v5 [' w
  39. def onKill (self,npcId,st):
    " J( J  ~+ l: h: `. Q. F' M! Y
  40. if npcId == KELTIR_NPC_ID:3 L( W4 U# {4 J
  41. n = getCount(st)
      Y) j1 n9 ]6 G( c1 a/ Z6 _
  42. if n == 0:, i/ ~* Z, G- c& x6 C( G  Q/ z' \& L( ^
  43. if st.get('chat0') == None :+ h8 r7 D1 H5 f, t% [% c
  44. st.set("chat0", "true")! S9 p, H# m7 c1 m& j
  45. return "Chat0.htm"
    ! w% L) d4 y1 r& o: |
  46. elif n == 1:
    " E9 x; y4 q8 o; j, w$ ?7 j! Z/ b- j; @
  47. if st.get('chat1') == None :$ N- U! u1 Q3 r% b
  48. st.set("chat1", "true")
    % m$ X% l! J8 w1 b
  49. return "Chat1.htm"/ O: V7 t  |; j) l$ [
  50. elif n >= 4:
    $ Z- ^; Q/ L, s, ~' V" g! t& ^# M
  51. return "Chat4.htm"- |- M- ~; d; \2 _
  52. return "Collect "+str(n)+" of 4 fangs"
    ( H4 o$ v( f8 G' u# K
  53. return/ ?4 I" v5 s2 a5 K* F; n* o6 E' S% A

  54. : v/ G) ~0 g8 m
  55. QUEST    = Quest(201, "Tutorial", "Tutorial quest")* ^2 S! x; y+ e% F& _+ a
  56. CREATED = State('Start',    QUEST)
    # \+ ^8 Q, t8 Z. a. f) }
  57. STARTED = State('Started', QUEST)$ ^. L+ U5 ~# a# H+ R, s( S2 j
  58. COMPLETED = State('Completed', QUEST)
    1 Y5 X8 a0 w1 A2 ]$ i7 f
  59. 0 y' R0 L4 H2 c1 Y5 i% B
  60. QUEST.setInitialState(CREATED)# I- u$ r2 v7 a1 A7 M1 }  h, h
  61. QUEST.addStartNpc(7056)
    & h+ M: p( @/ s) [
  62. QUEST.addStartNpc(7012)
    9 |% S' y( g* o% B0 p
  63. QUEST.addStartNpc(7009)
    / O- g" G; A! H1 f' p1 c
  64. QUEST.addStartNpc(7011)
    ' w; o; n  D# l

  65. ! t& C9 b  @* L1 Q# D$ N/ A
  66. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
    8 p  H; s. j/ z
  67. STARTED.addKillId(KELTIR_NPC_ID)
    1 z8 D) f- o7 E& U4 M2 Z5 D6 @# O. g" \
  68. STARTED.addTalkId(7056)
    & p' Z( S, [( ~. F
  69. STARTED.addTalkI d(7012)
    # \% {. q) ]- E; y
  70. STARTED.addTalkId(7009)
    , Z& D9 D: Q4 u: y
  71. STARTED.addTalkId(7011)
Скопировать код
& {9 X8 m- u4 C0 n+ Z$ ^
3 }) y7 O3 Z% Q' c8 B  _1 q





Добро пожаловать artace.ru - творческий сектор (https://www.artace.ru/) Powered by Discuz! X3.5