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

Название: Создаём собственные квесты (часть 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
  1. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста:: v1 U0 [; ^) b# h5 x5 t4 j0 s: n8 l
& V) P: a4 F. t. {( p
  1. if getCount(st) >= 4 :- p+ `( w' T% D; G" c/ i8 m
  2. completed(st)
    / m" @- X0 l/ E: `( v4 ]: \
  3.   return
    7 I9 @% R, P" p

  4. , V6 x1 ]* `4 u5 @6 h- @
  5. class Quest (JQuest):
    6 i- r5 |3 Y' Y6 U5 j
  6.   def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr): S, q, x9 n2 j" N7 A2 ^
  7.   def onEvent (self,event,st):' |9 {! X* h6 p1 {6 z' C) c
  8. id = st.getState()+ g) F" m! L8 L0 E
  9. if   id == CREATED  : st.setState(STARTED)9 I% C4 E6 E; u" ?) n  B
  10. elif id == COMPLETED: pass; q  u9 A& E1 A, S4 a/ x& v
  11. elif id == STARTED  : check(st)
    0 G) m( w$ W! j; }, }
  12. return
    + Q/ c9 c" c3 r2 j+ i( ~8 I
  13. $ N# v+ k8 R( N6 Y+ \9 N
  14. QUEST     = Quest(201,"Tutorial", "Tutorial quest")
    5 ~8 W3 T, I6 a* z
  15. CREATED   = State('Start',     QUEST)
    % {3 C  P3 b5 ~! I5 O
  16. STARTED   = State('Started',   QUEST)) h! Q( @* q1 ?1 c' b/ F4 D$ l) v" N
  17. COMPLETED = State('Completed', QUEST)2 P9 f2 ?1 c1 |9 `) \2 A- u5 s
  18. & M4 x& d( i3 ~; r6 C4 I9 n
  19. QUEST.setInitialState(CREATED)1 p! w* D1 g* g' ], Z/ A6 U
  20. QUEST.addStartNpc(7056)
    : B7 Z- z  G. h4 F: ?2 s/ s
  21. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Теперь рассмотрим, как это работает.: _, _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
  1. STARTED.addKillId(KELTIR_NPC_ID)
Скопировать код
и метод onKill в классе Quest:' r! Z% {: J+ m) K: R4 k9 @

) O  F2 W" T5 W; x( L+ v) Y, b6 D) h
  1. class Quest (JQuest):
    & C/ ]" k, X% K3 F
  2.   ...2 h" s5 E+ u' R! y. O* F" B) G  l
  3.   def onKill (self,npcId,st):8 V: u" L% Q* _- t" z' t
  4. if npcId == KELTIR_NPC_ID:
    : Z. m: U. }0 M5 ]: p7 f: L# Y9 I' O
  5.    n = getCount(st)
    3 A. t7 x7 W% G9 n
  6.    if   n == 0:
    $ k8 d8 I/ L$ }9 S4 Q
  7.        return "Chat0.htm"
      R. _  P- r/ e9 x  G7 u. u- @
  8.    elif n == 1:& U. I! M$ \3 i: B  _3 Y/ I
  9.        return "Chat1.htm"+ `# g( z- z5 ?- j0 m& \- {
  10.    elif n >= 4:, U# r) J% V) l5 q! p
  11.        return "Chat4.htm"  x* b. X7 ~; H( ^7 l3 L# x. G
  12.    return "Collected "+str(n)+" of 4 fangs"
    & R+ `% |' F6 O# [
  13. return
Скопировать код
Метод 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
  1. 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
  1. def onKill (self,npcId,st):
    - x) O9 }! _$ l
  2. if npcId == KELTIR_NPC_ID:
    * R. d9 z; Q( o' l3 c2 D
  3. n = getCount(st)
    & p) w8 B" R6 s* w! V- v
  4. if n == 0:
    * \4 @4 y, H; ~9 L" d
  5. if st.get('chat0') == None :
    , {- h  p" u3 o7 ~7 x
  6. st.set("chat0", "true")  K/ j6 l) l" B( j
  7. return "Chat0.htm"
    4 f& S6 j/ E4 {8 [$ U
  8. elif n == 1:
    $ [' X, X, `9 }9 B: ~( i
  9. if st.get('chat1') == None :
    1 _$ e$ M1 \' J4 ~3 ?
  10. st.set("chat1", "true")! v0 w9 W% d! A0 h
  11. return "Chat1.htm"
    . j- n) E' r  E3 ~- q) l
  12. elif n >= 4:
    1 l2 {! D) K1 R
  13. return "Chat4.htm"/ S! p/ D, u7 Y
  14. return "Collected "+str(n)+" of 4 fangs"( j, I3 x- _5 `/ _- l& z8 h& ^  v
  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.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
  1. import sys$ }. u! o' h7 n
  2. from net.sf.l2j.gameserver.model.quest import State
    ; s! ]* ^- m: T
  3. from net.sf.l2j.gameserver.model.quest import QuestState
    0 O$ W% t2 K# S* g! U3 T: v. y
  4. from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest
    $ l" g; _, c' J/ \
  5. - ~* P4 h& }% v2 C  Z4 k- C* ?
  6. KELTIR_NPC_ID = 12082
    ' ]+ l  \6 D- o, s5 I
  7. FANGS_ITEM_ID = 1859# `( m, K# {: a
  8. DROP_RATE    = 500000; d& {- L8 s' H

  9. 1 s9 t7 T3 Q% v4 j2 \" w. K- \
  10. WORLD_MAP_ITEM_ID = 1665
    : ]/ Q  `& I/ |; A% ]& x

  11. ) k' f7 G4 x! H) }( z0 T/ {
  12. def getCount(st) :: c" j2 H: Y7 p/ f9 J
  13. return st.getQuestItemsCount(FANGS_ITEM_ID)' {3 \( H0 e8 m4 |6 }- X
  14. * f3 s& h4 g" {4 x
  15. def completed(st) :
    5 y  w3 P1 V" n* u0 T' S. {
  16. st.setState(COMPLETED)
    , N( q1 \1 I$ M* S
  17. st.clearQuestDrops()! z' z2 l/ e$ N- e; _( z
  18. st.takeItems(FANGS_ITEM_ID,-1)7 j+ L3 l# l# V$ a+ d) s! u
  19. st.giveItems(WORLD_MAP_ITEM_ID,1)
    5 P  s( L6 f0 M' l! o
  20. st.exitQuest(False), b7 J/ E, ?$ R& a. A! I) \8 @
  21. return8 m8 f$ ~" K7 h, b, n8 Z2 Q- S7 a

  22. 6 z5 Z# q+ E' Z9 i1 p% v" C- _3 G
  23. def check(st) :* i( s) i8 q# |2 r5 e/ T# J
  24. if getCount(st) >= 4 :
    8 _/ I! x0 V2 H( U- j* T6 n
  25. completed(st)8 I* @9 N# @4 W* n1 U0 F  b. D
  26. return( I! K- w  F& L" y3 R3 q- N
  27. ( G8 I" V7 b: y+ r
  28. class Quest (JQuest):
    ; P. E2 t' S( s$ t. W1 W7 o
  29. 8 w3 `, C2 w6 d; U+ }$ f
  30. def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)+ C: L: U( m/ V' ?- r- |5 c) e

  31. , Q, U7 D  M$ \
  32. def onEvent (self,event,st):
    * U" n" Q6 ^- c% g
  33. id = st.getState()
    : d( O7 J  G$ s! u
  34. if id == CREATED : st.setState(STARTED)8 P: |1 ^+ f2 y6 Z
  35. elif id == COMPLETED: pass- _7 Q. M7 Z- w" h4 g% n: `
  36. elif id == STARTED : check(st)
    " C. u' i0 W4 |
  37. return! Q- C& }  t* s0 L) o0 Q7 Z" O
  38. ' e8 A; _! @& I  [% N
  39. def onKill (self,npcId,st):
    - ~. e9 e1 n" e- r; k7 e
  40. if npcId == KELTIR_NPC_ID:' C; w+ E: y2 {% Y& j9 L$ Z
  41. n = getCount(st). A4 S3 p% X$ ~7 N
  42. if n == 0:9 T2 C' y' M$ n: n6 y
  43. if st.get('chat0') == None :
    6 _# ?# i: [$ x2 I& S' {
  44. st.set("chat0", "true")
    - X+ {1 D" U5 e
  45. return "Chat0.htm"& k5 G7 j: B7 g4 H, E
  46. elif n == 1:
    3 d( Y/ w3 @9 R  o! L, {
  47. if st.get('chat1') == None :
    - C" j. b' {% ?' b1 N( S' q5 `
  48. st.set("chat1", "true")8 K" `( W& E8 n" X
  49. return "Chat1.htm"# c; ~7 x' g% i, ]4 s( l4 _
  50. elif n >= 4:
    ) j0 V  {% {  |  z  E
  51. return "Chat4.htm"+ u% ]* S9 `% T% V, v4 ^7 t8 v; W. O
  52. return "Collect "+str(n)+" of 4 fangs"
    $ |; k, K% _) [" w. z( ?1 j
  53. return
    - V8 F: t  J! r0 Y

  54. 2 _/ q. {" v/ g2 I
  55. QUEST    = Quest(201, "Tutorial", "Tutorial quest")
    % ]& D: W9 f; n
  56. CREATED = State('Start',    QUEST)
    / Q" {2 w$ A( E) \" Q
  57. STARTED = State('Started', QUEST)  q) I% ^- d: o5 D% R2 F
  58. COMPLETED = State('Completed', QUEST)
    2 b  A! F0 P. P: N3 O+ T' V3 k  }
  59.   o# s- P: s) \9 a
  60. QUEST.setInitialState(CREATED)
    - G! V+ u9 b, K3 N$ J; `
  61. QUEST.addStartNpc(7056)
    2 L& L$ m, E8 _/ @
  62. QUEST.addStartNpc(7012)
    2 F  u' U) Z) P' U9 S
  63. QUEST.addStartNpc(7009)8 v$ }; W& y- _" W& p; s
  64. QUEST.addStartNpc(7011)4 A" l4 O3 i8 \' s7 R
  65. + \( }% f2 U9 E  _# U
  66. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)' C$ H; H, e% F$ v) q, U2 f
  67. STARTED.addKillId(KELTIR_NPC_ID)+ t1 H: j: _; H* |9 K+ c
  68. STARTED.addTalkId(7056)/ S8 g  g. N7 B! q2 q0 w
  69. STARTED.addTalkI d(7012)
    ; `' i# c3 J" X4 x+ G. S  V
  70. STARTED.addTalkId(7009)
    6 K9 B0 W8 W0 i! h- [( A
  71. STARTED.addTalkId(7011)
Скопировать код
! ?2 ?) N. @0 \9 u+ f1 t

8 P. |% ?6 W6 b( k




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