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

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

Автор: admin    Время: 2024-9-17 19:36
Название: Создаём собственные квесты (часть 2)
Хроники        Interlude
0 W  ~) N- q7 ~( g# n4 X8 A( |Сборка        L2j
# n$ `. `: }4 G! F8 MОбратите внимание: в файле htm стартового NCP обязательно должна быть ссылка на квест:
; Q' j3 M1 [' W# t' u$ @6 I  X
  1. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста:
2 ?7 b1 n( A- [
2 ?6 q" p( R* C5 f% t" W/ t
  1. if getCount(st) >= 4 :
    $ d5 C+ g7 r! [* ~) b8 a
  2. completed(st)
    4 a- I: c5 j( j; n$ K0 n4 N
  3.   return
    9 f( L. \- k1 ^) I+ I

  4. 8 x+ I/ \# t+ q' j$ n0 {4 X9 b3 ]
  5. class Quest (JQuest):9 ]) J2 d  T# N$ J+ O) z: C
  6.   def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)
      }; Y+ g3 T+ a( W. p  y+ r7 F1 l
  7.   def onEvent (self,event,st):
    4 |* w% [4 l5 o/ a7 A% t$ Y7 N+ D, Q
  8. id = st.getState(); L+ D( n8 `' D
  9. if   id == CREATED  : st.setState(STARTED)% L& O) R( \4 e7 X
  10. elif id == COMPLETED: pass
    ! E; w) y. H: a: X
  11. elif id == STARTED  : check(st)
    # v9 I6 ~) {- N0 s1 b
  12. return' G& M# y  T$ O3 E/ o( `

  13. + F* x* |: e4 K7 s% L1 r
  14. QUEST     = Quest(201,"Tutorial", "Tutorial quest")
    / L5 Z/ {3 O' x, D* ^5 w
  15. CREATED   = State('Start',     QUEST)' a: @1 R4 F" J0 `# `
  16. STARTED   = State('Started',   QUEST)2 g; l6 s- I5 q% X
  17. COMPLETED = State('Completed', QUEST)1 P, B: \" v8 L, x7 }- a
  18. ' Q7 s) y. U- b7 K( B( X1 w
  19. QUEST.setInitialState(CREATED)
    1 i: i  z! C3 O' L) _: R9 R- V
  20. QUEST.addStartNpc(7056)) {% e& t$ M) @( Z
  21. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Теперь рассмотрим, как это работает./ q; m% f3 s0 L0 k( W
Игрок подходит к начальному NCP (в данном случае 7056), нажимает на «Quest». Квест будет создан и состояние квеста перейдет к CREATED и игроку будет показана страничка Start.htm с описанием квеста. Тогда метод onEvent, поле открытия странички Start.htm переведет состояние квеста в STARTED и игроку будет показана страничка Started.htm, где будет опсание того, как найти keltirs и .т.д.
8 x" T% m  a* q& l
! S, s/ ?  J- \: r" y! M
# z1 @% ^3 [' ?' Q8 Y
При состоянии STARTED будет зарегистрирован дроп «fangs» при убийстве keltirs. Игрок может вернуться к стартовому NCP и спросить о квесте – метод onEvent будет вызван снова. Если у игрока не хватает необходимого количества предметов, то метод check() не переведет квест в следующее состояние и Started.htm будет показана снова. Но если игрок собрал необходимее количество предметов (в данном случае 4 клыка), то метод check() вызовет метод completed() который переведет квест в новое состояние COMPLETED, заберет все клыки, даст карту мира, т.к. это награда за квест, покажет Completed.htm и завершит квест.
* f1 b* n4 d/ N: S7 Z# g
3 \' O" \8 U; Q3 G7 B3 }

2 a: b' [6 ?" O# RТеперь давайте сделаем наш квест более похожим на то, что он должен из себя представлять.
0 a  x( C! {. p, PПрежде всего у нас есть 3 метода для объявления их в Яве – onTalk, onKill и onEvent. Если методы onTalk и onKill не объявлены, то за них все будет делать метод onEvent, т.е. определять квестовых монстров и вызывать диалоги NCP. Есть примечание, методы onTalk и onKill будут вызывать только диалоги с NCP в зависимости от текущего состояния квеста. Метод onKill будет вызываться только тогда, когда мы убиваем квестового монстра.
+ u; U  l- o: T* U  i$ d) f" D# N8 L

8 O. |+ ?( i3 a! ]$ D  u$ [2 \3 B6 qДавайте рассмотрим как вызывается метод onKill при убийстве keltir в состоянии квеста STARTED:
9 I6 \% Z& s/ Q$ f. l. F
  1. STARTED.addKillId(KELTIR_NPC_ID)
Скопировать код
и метод onKill в классе Quest:# x% k' |5 s, w) D$ i
, J" g; b1 B7 p( _5 o4 @" j+ G
  1. class Quest (JQuest):2 l! k, D* i4 m" a4 E$ B1 \
  2.   ...
    ) B# h) f$ }- a/ v( \
  3.   def onKill (self,npcId,st):
    ) m3 |' L+ M$ e  l* I3 y9 W
  4. if npcId == KELTIR_NPC_ID:
    ' [. g6 H2 ]# g4 Y9 u" [6 d
  5.    n = getCount(st)
    3 ^) {) J6 b9 ]3 j% L$ c
  6.    if   n == 0:4 K; n- B8 r8 z
  7.        return "Chat0.htm"- m7 [3 v  Z3 \0 T  i0 n
  8.    elif n == 1:9 y5 L$ M! L7 z" I/ b5 _* D
  9.        return "Chat1.htm"1 d. U8 F" `0 j6 ~0 K
  10.    elif n >= 4:
    9 `* ]0 ]/ c& l2 X9 y
  11.        return "Chat4.htm"
    & O( g- Z. x& i7 M9 R
  12.    return "Collected "+str(n)+" of 4 fangs"
    7 d4 l9 c9 x5 q, |2 t- L
  13. return
Скопировать код
Метод onKill (а так же метод onTalk) имеет следующие параметры:: P% K$ p# R8 s. l% @& R
4 ]$ I" x4 E' E; x* E1 p! |. b
3 d/ L: `, s) W# N5 A( E
• self – квест6 z' |& k; H6 n7 _2 K
• npcId – ID NCP, которого мы должны убивать (если это метод onTalk, то ID того NCP, с которым мы должны поговорить).
: j6 G1 M' Y- A  z( q$ L& J• st – текущее состояние игрока.: B$ t5 a+ B) O7 y

" Z% j: k+ A) e/ n
" |, R/ {; j) g: U- J( d/ d
В этом методе мы проверяем и отмечаем, является ли убитый NCP keltir’ом. В основном эта проверка не нужна, т.к. у нас только KELTIR_NPC_ID.
( p( X+ D6 f- v+ i& z0 K
& K) w0 U: H; T! _) R7 [
, ]1 k* a9 `8 J. Q0 p
Затем проверяем количество предметов (в данном случае количество клыков), и если их вообще нет, то возвращаем строку "Chat0.htm", если только один предмет, то возвращаем строку "Chat1.htm", если же предметов 4 или больше, то "Chat4.htm". Если строка возвращена из методов onEvent, onKill или onTalk, то сервер покажет соответствующие htm. В Chat0.htm может иметь следующий текст: «Вы не имеете ни одного клыка, возвращайтесь позже, когда соберете 4 штуки и бла, бла, бла…», в Chat1.htm может быть следующий текст: «У Вас всего 1 клык, по этому соберите еще…». В Chat4.htm – «Вы собрали необходимое количество предметов, возвращайтесь к вашему тренеру, что бы завершить квест…»
' T; x4 e$ h6 l3 g# [- l" ~& p! ]& Q( z2 A& ?/ f0 G. V

9 [% u0 u/ J5 [Примечание: если в строка return начинается с "<html>", то будет показана страничка html с текстом, который стоит далее. Так вместо:$ n  Y. e- h0 L: D8 u- ?9 o6 v
return "Chat4.htm"5 @' Q4 I7 Y* X) k& H0 U/ q

# M3 f! S  }* d$ V( u
- H( \+ ^4 ?7 ~6 {3 q" C( O
можно поставить:
5 E% T& l# W0 Z8 P. F8 B+ }9 b; c* x
  1. return "<html><body>Return to your trainer to complete the quest</body></html>"
Скопировать код
Так же если строка заканчивается без .htm или в начале нет <html>, то текст будет выведен, как системное сообщение в окне чата. В нашем случае мы сделаем так, что бы при каждом убийстве keltik выводилось системное сообщение: «Собрано N из 4-х клыков».
$ o. [! t% p2 K9 J5 v. n7 v
8 D- N4 L6 E3 h, X: `! Z& `

' p& D% ^; H0 Y0 u! h* s8 zНаш код для onKill имеет один недостаток. Он будет постоянно показывать Chat0.htm, Chat1.htm и Chat4.htm, нам же необходимо, что бы Chat0.htm и Chat1.htm показывались только один раз. Как нам это сделать? С помощью переменных.! _; t4 X% c- r7 q* n) p
' _* b: w" _8 C' \
: q# b. O* m5 T$ V
В каждом квесте строки могут храниться с помощью переменных. Эти переменные сохраняются в Вашей БД. В каждом методе мы можем назначить, прочитать и удалить переменные. Давайте изменим метод onKill, так что бы каждый диалог вызывался только один раз.
; z3 k1 U4 r4 Y. Y
  1. def onKill (self,npcId,st):
    ; o' c* s2 F7 @1 I/ f
  2. if npcId == KELTIR_NPC_ID:
    0 ?4 o1 a  v0 B5 u
  3. n = getCount(st)
    ' d6 M' {- ]* k$ i- F
  4. if n == 0:* {- h* ?( b5 @) e! D( i6 ]+ d
  5. if st.get('chat0') == None :
    $ }: ~" \& G# O; q, Q" B+ P
  6. st.set("chat0", "true")
    , S, i+ j4 R4 k& s$ M
  7. return "Chat0.htm"
    1 F) S6 m" r) S6 w; Y
  8. elif n == 1:0 l' f3 c  ~- z# x! q; s) J% m! q' g0 N
  9. if st.get('chat1') == None :7 H( x9 i& ~. c9 e
  10. st.set("chat1", "true")4 A# i1 S8 N3 a6 j3 A7 I
  11. return "Chat1.htm"% {8 `+ F+ u* i  @. a( j
  12. elif n >= 4:8 X! M/ M- S/ l, E2 o
  13. return "Chat4.htm"
    " Q6 b/ G& I5 {% L  A
  14. return "Collected "+str(n)+" of 4 fangs"& w" A; h* h. A( ~6 k1 j
  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.
3 p- N% y. U% y- [; T, x! k1 I( R% t4 m( z# D) P
( m% U7 A' [, I- ]4 i# m
Вот конечный рабочий вариант квеста:2 [! k0 e: v/ E# m& _5 V
  1. import sys7 A8 w# ^% ]/ K
  2. from net.sf.l2j.gameserver.model.quest import State
    $ c& }$ T, X7 U+ S6 N, ?8 |7 r7 g  x
  3. from net.sf.l2j.gameserver.model.quest import QuestState
    & l2 H7 ~) c2 G2 f! R9 b* d
  4. from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest
    ! U) }' A9 G) D- t5 r$ L
  5. , O( z! v1 u$ j
  6. KELTIR_NPC_ID = 12082+ S. n* i( a0 M. c, v
  7. FANGS_ITEM_ID = 1859
    5 e, R# w  L) V0 p2 k
  8. DROP_RATE    = 500000
    . u  g6 Z, V' d% y' K

  9. 7 z: n" ^* S* l9 y* J/ y, t$ u
  10. WORLD_MAP_ITEM_ID = 1665
      a9 p. U6 l; ]* q  S5 M8 P; ^, m

  11. " ?( W% B/ F! J9 [+ A! r1 T) I3 M
  12. def getCount(st) :
    1 d2 ?* y$ P7 i- b
  13. return st.getQuestItemsCount(FANGS_ITEM_ID)4 V  }1 ?* {& M9 ~! g

  14. # T# b0 G7 f% \8 l* k1 Q. y8 N
  15. def completed(st) :
    & z, O  t: {& [% F
  16. st.setState(COMPLETED)
    # v, i+ s( t9 p) r. d
  17. st.clearQuestDrops()
    ) d+ M1 k$ I% L" `, [' Q: ?. G% w
  18. st.takeItems(FANGS_ITEM_ID,-1)
    3 c  i1 ?: d. _- A
  19. st.giveItems(WORLD_MAP_ITEM_ID,1); ^! ]2 E( j  D0 Q( @
  20. st.exitQuest(False)6 A: O9 ~9 |. {: n, N
  21. return
    2 W( Y8 n/ B( E. X3 n4 f3 K

  22. * }$ D' W# z. |( F% _: R" h9 W
  23. def check(st) :
    6 B9 W) b2 X& K3 G
  24. if getCount(st) >= 4 :2 \( x2 o" Q6 A% m3 n
  25. completed(st)
    3 z" B5 A( Q2 A9 p1 \/ |- f% j
  26. return
    / Y7 }+ x( n5 f+ P+ W
  27. 8 ?, d/ K$ j9 K6 @
  28. class Quest (JQuest):* K; J0 _" w: L9 u. j9 F3 G- W
  29. 2 R4 x, J6 S7 o
  30. def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr): [0 R: Y; x( f

  31. 9 A0 [! ^+ _# R' d  ^4 o' _
  32. def onEvent (self,event,st):
    ) I) }8 @  d( U: w7 ^
  33. id = st.getState()
    ' x% _0 Z' x$ c. t$ ?5 ^5 Y! j- M
  34. if id == CREATED : st.setState(STARTED)  b4 {7 L8 M# ?' g: {. m
  35. elif id == COMPLETED: pass" O' t. J5 \' i" T4 _
  36. elif id == STARTED : check(st), J) ?1 M6 T& u: B% f% \
  37. return
    3 |2 d* W, j" C, [# |& [

  38. 3 I  i" ?! ?/ |
  39. def onKill (self,npcId,st):% b* P( O. m2 l3 a" B
  40. if npcId == KELTIR_NPC_ID:+ ^! ]+ y, O: S
  41. n = getCount(st)
    3 J4 W$ R+ q( P2 q$ B
  42. if n == 0:
    " Q' X$ E1 |( z& z
  43. if st.get('chat0') == None :
    * }5 C( s7 D8 G
  44. st.set("chat0", "true")6 p. a3 c, C0 S
  45. return "Chat0.htm"
    ; ~& a2 t9 ^1 C. n1 N) O3 {
  46. elif n == 1:+ a$ f7 R$ [+ ^' P
  47. if st.get('chat1') == None :" s8 h& o" f. r" Y' z
  48. st.set("chat1", "true")
    * N0 b0 o0 @: l/ s- ?
  49. return "Chat1.htm") ^- ?( l8 }: d/ A# V
  50. elif n >= 4:- `9 Y' u* \9 W
  51. return "Chat4.htm") ~' d) D: O+ q0 t5 M
  52. return "Collect "+str(n)+" of 4 fangs"; V$ @! T6 U) P* e1 Y7 o
  53. return
    # I7 l0 w4 Q6 }5 Z) a
  54. " g( Y# W* C; q3 q+ x) l
  55. QUEST    = Quest(201, "Tutorial", "Tutorial quest")* G/ E& U' t0 b  Z- F
  56. CREATED = State('Start',    QUEST)' v. l! Z0 _  D4 C- S% G! l" S6 r
  57. STARTED = State('Started', QUEST)
    + S' n/ n: T6 u3 Q& ]- W$ R
  58. COMPLETED = State('Completed', QUEST)
    9 M+ \' o* d" A7 \
  59. 7 l& i) _" i2 K9 K; P5 P  }, h
  60. QUEST.setInitialState(CREATED)) K( e3 p  ]8 Q1 h. g( L$ |9 r4 j
  61. QUEST.addStartNpc(7056)
    7 c: n& R! G  S9 m; {
  62. QUEST.addStartNpc(7012)
    5 |) b) C5 w  U! m( k& B- n
  63. QUEST.addStartNpc(7009)2 m' W2 ~1 v) R7 X9 O
  64. QUEST.addStartNpc(7011)
    7 R# W8 r0 N0 O# }: v

  65. 8 u# v8 y7 w, _" T4 ]
  66. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)/ f& q9 T7 G  {6 W& w$ \# H
  67. STARTED.addKillId(KELTIR_NPC_ID)
    , V# v5 n" I. ^% g9 H& Z- y: ~
  68. STARTED.addTalkId(7056); [; r6 W& }7 j" W- |  w
  69. STARTED.addTalkI d(7012)/ F9 \6 b9 ?, ~
  70. STARTED.addTalkId(7009)
    % g: v3 K6 v9 O/ d
  71. STARTED.addTalkId(7011)
Скопировать код

3 a, A. {( x) w# ]2 o
0 p1 n4 c3 `6 f* Z




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