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

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

Автор: admin    Время: 2024-9-17 19:36
Название: Создаём собственные квесты (часть 2)
Хроники        Interlude
1 v1 C6 Q, F4 kСборка        L2j
: o" {# d; c/ r' G) G$ v9 _Обратите внимание: в файле htm стартового NCP обязательно должна быть ссылка на квест:3 @; k/ J( c7 R6 l" v. E/ P9 P
  1. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста:: R: C+ t. ^4 l/ @& _
7 \# m0 z1 u& y
  1. if getCount(st) >= 4 :
    : H- C& b/ v5 A$ T; h3 D/ S- ?
  2. completed(st): Z: G, {; L: ]1 `+ x
  3.   return, W* |+ c: u' f8 c9 c
  4. ) J0 s0 e! V0 r! c' e
  5. class Quest (JQuest):4 ]; k* O  J+ q3 M
  6.   def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)7 Q4 Z+ ]3 }  ?
  7.   def onEvent (self,event,st):
    * m/ Y- g0 Y3 ?3 r- E6 `0 E
  8. id = st.getState()
    4 H$ j; t/ i* C* X6 K7 n# @& l2 q
  9. if   id == CREATED  : st.setState(STARTED). W  G4 S: ]  `* W6 h$ D8 \; A
  10. elif id == COMPLETED: pass
    4 c2 l: a5 Z+ J- k  v1 h
  11. elif id == STARTED  : check(st): |) N4 y# P( D3 r+ l
  12. return
    ( ^; O3 |3 I1 }* u1 A$ X1 }$ [  N
  13. 9 v" C& k9 U' D  `# Y, Q
  14. QUEST     = Quest(201,"Tutorial", "Tutorial quest"); m  l$ V# N1 b' l" I+ _
  15. CREATED   = State('Start',     QUEST)
    7 w& l) y, m( k$ G  v( n9 _" |
  16. STARTED   = State('Started',   QUEST)9 ~& M3 w( }6 D# C
  17. COMPLETED = State('Completed', QUEST)7 \$ B7 V, U  k5 K" _
  18. 9 _9 m2 O: B5 ]" l
  19. QUEST.setInitialState(CREATED)
    / I, u  E2 x2 l$ ]& z. ^; m# p
  20. QUEST.addStartNpc(7056)" B# h% R2 p  Y$ j
  21. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Теперь рассмотрим, как это работает.$ C8 j/ l+ j2 [0 G, @2 v2 I$ _
Игрок подходит к начальному NCP (в данном случае 7056), нажимает на «Quest». Квест будет создан и состояние квеста перейдет к CREATED и игроку будет показана страничка Start.htm с описанием квеста. Тогда метод onEvent, поле открытия странички Start.htm переведет состояние квеста в STARTED и игроку будет показана страничка Started.htm, где будет опсание того, как найти keltirs и .т.д.9 q# ^& |0 e4 M# O
. \7 z( N# M( ^; H* D! E1 Z: t

( ]/ v: T2 t2 RПри состоянии STARTED будет зарегистрирован дроп «fangs» при убийстве keltirs. Игрок может вернуться к стартовому NCP и спросить о квесте – метод onEvent будет вызван снова. Если у игрока не хватает необходимого количества предметов, то метод check() не переведет квест в следующее состояние и Started.htm будет показана снова. Но если игрок собрал необходимее количество предметов (в данном случае 4 клыка), то метод check() вызовет метод completed() который переведет квест в новое состояние COMPLETED, заберет все клыки, даст карту мира, т.к. это награда за квест, покажет Completed.htm и завершит квест.
. e1 h0 z. d) n% c' s* c  X1 {; c6 u
. _% _* K7 t  v" I3 l6 i
Теперь давайте сделаем наш квест более похожим на то, что он должен из себя представлять.
; D5 z6 M: z: K8 u$ S/ {$ _Прежде всего у нас есть 3 метода для объявления их в Яве – onTalk, onKill и onEvent. Если методы onTalk и onKill не объявлены, то за них все будет делать метод onEvent, т.е. определять квестовых монстров и вызывать диалоги NCP. Есть примечание, методы onTalk и onKill будут вызывать только диалоги с NCP в зависимости от текущего состояния квеста. Метод onKill будет вызываться только тогда, когда мы убиваем квестового монстра.1 q) z7 A' a9 x, w5 d% T6 h
* L* g: B- r; ]9 l$ Q. V

& w7 I3 R2 A5 V; r2 o7 h$ T. nДавайте рассмотрим как вызывается метод onKill при убийстве keltir в состоянии квеста STARTED:
) s" ?/ b9 m/ E! ]3 i/ G
  1. STARTED.addKillId(KELTIR_NPC_ID)
Скопировать код
и метод onKill в классе Quest:
7 c! X* M( u4 Y% h3 h4 a) c; Y9 ^6 q2 Q! k5 Z# F
  1. class Quest (JQuest):$ s8 ]* ?1 m8 \' K) |+ [- n9 V  {
  2.   ...
    / l1 _1 s8 v' I9 x: v' s- v
  3.   def onKill (self,npcId,st):  R( d7 n+ q+ |+ h9 k/ Z* q
  4. if npcId == KELTIR_NPC_ID:4 C7 X& O2 i" c# M: q9 D" q
  5.    n = getCount(st): L/ Z" t! n6 ?; k2 d# w
  6.    if   n == 0:- n6 P1 O! {* ~- d) @
  7.        return "Chat0.htm"
    + E* _6 D, u$ u$ `! h- H1 F
  8.    elif n == 1:
    ( B$ S$ w! ~6 j) T
  9.        return "Chat1.htm"! @( S- `7 A3 P" z
  10.    elif n >= 4:
    % P4 ^7 O) u! `
  11.        return "Chat4.htm"
    ' [9 A+ y, v+ j$ [
  12.    return "Collected "+str(n)+" of 4 fangs"
    " ]$ s7 x4 o; q+ |. z& ?7 T5 g
  13. return
Скопировать код
Метод onKill (а так же метод onTalk) имеет следующие параметры:
7 H# V- Q7 a5 ?  A2 T; i
& p/ r) G7 b. j2 y

' D. i, E  `/ q3 g5 ]• self – квест
, b5 D) S0 L/ _, G. b• npcId – ID NCP, которого мы должны убивать (если это метод onTalk, то ID того NCP, с которым мы должны поговорить).% F9 o" k# [) Q$ w
• st – текущее состояние игрока., |0 x2 ]& [: X- ^, J2 h5 H

8 B0 k8 _( m. A
. D3 p( w# u# D6 c) z9 {' C5 ^
В этом методе мы проверяем и отмечаем, является ли убитый NCP keltir’ом. В основном эта проверка не нужна, т.к. у нас только KELTIR_NPC_ID.# A6 h& p/ Y: {/ P5 J! a

5 {8 v  l; x! M/ v

: W. q2 w9 B$ C; D. M2 o5 T6 T0 w7 jЗатем проверяем количество предметов (в данном случае количество клыков), и если их вообще нет, то возвращаем строку "Chat0.htm", если только один предмет, то возвращаем строку "Chat1.htm", если же предметов 4 или больше, то "Chat4.htm". Если строка возвращена из методов onEvent, onKill или onTalk, то сервер покажет соответствующие htm. В Chat0.htm может иметь следующий текст: «Вы не имеете ни одного клыка, возвращайтесь позже, когда соберете 4 штуки и бла, бла, бла…», в Chat1.htm может быть следующий текст: «У Вас всего 1 клык, по этому соберите еще…». В Chat4.htm – «Вы собрали необходимое количество предметов, возвращайтесь к вашему тренеру, что бы завершить квест…»
) g; b0 E6 F0 i/ i1 g: F5 K7 g+ U' Z
* Z: D4 I' V3 R. W$ H" @3 L8 n

7 o" c7 p7 X+ SПримечание: если в строка return начинается с "<html>", то будет показана страничка html с текстом, который стоит далее. Так вместо:
4 g' X- b5 j0 Treturn "Chat4.htm"
9 m+ U6 J8 `! j) Y1 L) l
; L2 |% T2 S* t* F
! N, X' c! i8 ]9 R1 D7 Y. S3 R1 h
можно поставить:
5 A0 s# R  r" u& l* x
  1. return "<html><body>Return to your trainer to complete the quest</body></html>"
Скопировать код
Так же если строка заканчивается без .htm или в начале нет <html>, то текст будет выведен, как системное сообщение в окне чата. В нашем случае мы сделаем так, что бы при каждом убийстве keltik выводилось системное сообщение: «Собрано N из 4-х клыков».
$ K6 Q" t: d( G' Y8 Q6 _
" E  j- i! T3 K3 ]% u2 h3 i
2 j; g+ I3 d2 |% e8 ^
Наш код для onKill имеет один недостаток. Он будет постоянно показывать Chat0.htm, Chat1.htm и Chat4.htm, нам же необходимо, что бы Chat0.htm и Chat1.htm показывались только один раз. Как нам это сделать? С помощью переменных.) V* z- v- m) J& L2 c* M- {- R
1 K) m1 V) y) i4 \- h! ?7 c

. [, b2 H6 A. }( ^В каждом квесте строки могут храниться с помощью переменных. Эти переменные сохраняются в Вашей БД. В каждом методе мы можем назначить, прочитать и удалить переменные. Давайте изменим метод onKill, так что бы каждый диалог вызывался только один раз.
6 G8 d- O2 q- h& G* L
  1. def onKill (self,npcId,st):+ X6 A. u2 p8 }* P- k
  2. if npcId == KELTIR_NPC_ID:+ M. X( `" j* N+ ~
  3. n = getCount(st)
    4 ~1 k3 H. N& e9 I8 a' e
  4. if n == 0:
      Y4 K4 [  b2 U
  5. if st.get('chat0') == None :
    3 ~. G% [# H- ~+ `0 c6 a
  6. st.set("chat0", "true")
    ! z% M5 `9 F0 U' L- x
  7. return "Chat0.htm"
    ) o3 r1 p9 D9 [$ X' {+ X/ U8 u
  8. elif n == 1:  ~; x& @8 s9 G8 d9 B: ]
  9. if st.get('chat1') == None :+ H6 i8 n& x8 f+ G
  10. st.set("chat1", "true")
    ) x/ b5 t" H2 Z  z% S
  11. return "Chat1.htm"8 C5 |3 u0 {/ W8 {# h3 [$ [
  12. elif n >= 4:: U& P: D& y9 U, z/ L$ H2 E5 Y
  13. return "Chat4.htm"
    & L( x# F3 L4 f  y3 a, T
  14. return "Collected "+str(n)+" of 4 fangs"" c8 [- |: G, D. h$ K
  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.
% w7 t! d! I0 F/ u
: W+ `1 X; z' p6 i( |

* Z! p5 C, U, N3 ?! PВот конечный рабочий вариант квеста:
) @+ S; s" F' X! c9 w
  1. import sys& B, N3 I4 v' M. D
  2. from net.sf.l2j.gameserver.model.quest import State
    2 \$ {* o1 `" Q
  3. from net.sf.l2j.gameserver.model.quest import QuestState5 S& k& h' m; \* Y
  4. from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest0 D; }$ P* O8 }& ^' f' ^- k
  5. 7 O6 i$ ]0 T& H% L7 u
  6. KELTIR_NPC_ID = 12082
      @; G+ W5 E$ d. q! a% P
  7. FANGS_ITEM_ID = 1859: Y2 o* f2 y  z) r0 e4 O6 r4 k2 I
  8. DROP_RATE    = 500000& C+ R' s! \6 d5 w: a3 n
  9. # T, X( D8 L3 `7 }. }8 K- W& Y
  10. WORLD_MAP_ITEM_ID = 1665) @3 m* c4 Q; e2 [  {) z9 |( L  M2 p) {
  11.   Y1 p/ C) [' O9 [3 w
  12. def getCount(st) :2 g9 s7 S5 \+ p% r. h) U3 w
  13. return st.getQuestItemsCount(FANGS_ITEM_ID)
    " Q" M( S' k' q6 |( Y4 k. \

  14. & b9 ]. f: H& a8 {& x4 ~* ?
  15. def completed(st) :& w8 [* _& R+ j9 z( @* w
  16. st.setState(COMPLETED)
    4 ~' ~' z7 A! v7 X
  17. st.clearQuestDrops()
    ' P, v0 p  H. O$ T
  18. st.takeItems(FANGS_ITEM_ID,-1)
    : z$ D" Y; V( t! T, ]
  19. st.giveItems(WORLD_MAP_ITEM_ID,1)( m" Y( ~# j6 G; ^9 {1 x: z. M
  20. st.exitQuest(False)9 x) x! r/ z+ I0 J
  21. return
      c" E+ y3 ^' y/ O  P, }  N; _
  22. + y' l# j+ ]: @5 ]) [3 Y$ K$ n
  23. def check(st) :7 k( t; @$ A  W% x# q# i6 Z' H, c( o
  24. if getCount(st) >= 4 :
    3 E, @% Y5 r- B7 A, b( ]
  25. completed(st): w% M8 p0 k$ p0 F' y4 z
  26. return
    & t* Y, j9 L: S: d* G5 P% Z
  27. $ S; S# \* X' _! _8 p
  28. class Quest (JQuest):2 @- w" M8 W0 `5 ^; S- Q6 g

  29. ) B$ U+ w2 t! c1 A/ J# w
  30. def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)
    + U  o) g& }" i9 S  e' T" m

  31. . M* {9 _* K3 l2 p9 E; h
  32. def onEvent (self,event,st):
    ; H- W& N: |0 N6 l8 g' G! t
  33. id = st.getState()
    % W# r: N* J! D% ?* m0 P% u
  34. if id == CREATED : st.setState(STARTED)
    5 L5 m3 W/ v$ W  C/ N
  35. elif id == COMPLETED: pass
    + O, @$ _) T1 X" w
  36. elif id == STARTED : check(st)
    ( n8 _# T2 ]0 j: m4 W  P2 q
  37. return2 s2 A5 C6 O' q' M% D
  38. # _* M+ v7 K) |( a5 a8 e% ]3 n
  39. def onKill (self,npcId,st):
    + l0 h; ~$ y9 F/ B& T
  40. if npcId == KELTIR_NPC_ID:
    ! V" V4 r) O4 M; Y# |  B
  41. n = getCount(st)
    : T, D' T1 a# \2 P$ z2 ?& O) K
  42. if n == 0:
    7 j" |8 P' ?! V9 ^& h( O) \
  43. if st.get('chat0') == None :
    ; M9 b% J' N% N) l
  44. st.set("chat0", "true")
    : I3 O5 U* C5 e
  45. return "Chat0.htm"4 w, m$ G# R+ M  D8 G4 g
  46. elif n == 1:3 O" W( x; h2 s( E
  47. if st.get('chat1') == None :, [3 @2 U$ _3 `, O2 O. ?. R
  48. st.set("chat1", "true")
    ) o+ S. a% u1 U3 }; N1 @$ d, z/ ~
  49. return "Chat1.htm") u  A% x6 A' E( {. ~' y! |
  50. elif n >= 4:( _# U* c9 X# P! B- N4 B+ N3 ~
  51. return "Chat4.htm"
    & Q( Z- _0 ~8 u  G
  52. return "Collect "+str(n)+" of 4 fangs"
    : Z2 [9 U9 M, T: @8 I3 ]2 J
  53. return
    3 Z; O* _. l5 l3 ~

  54. ) C# t0 ], g: d+ L, S( `) ^- a
  55. QUEST    = Quest(201, "Tutorial", "Tutorial quest")
    9 E+ o6 _" {' q* \4 P$ V) ]8 T7 G) z* O
  56. CREATED = State('Start',    QUEST)7 J+ d  K% B& s, ?% g. G6 Y) V
  57. STARTED = State('Started', QUEST)
    ( |9 q% Q( O0 W# C) l! C% T
  58. COMPLETED = State('Completed', QUEST)
    ! y+ m- e4 f: o

  59. ) q" v% }& a/ R+ X4 v" O
  60. QUEST.setInitialState(CREATED)
    3 i, B. t! E+ O# w# ]& _. m9 i
  61. QUEST.addStartNpc(7056)
    - B- _+ f1 {- X. R5 @
  62. QUEST.addStartNpc(7012)/ Y$ [( Z1 `, u) q
  63. QUEST.addStartNpc(7009)4 o4 H2 u- Q1 ]! e& y" h' o5 I. h: Q
  64. QUEST.addStartNpc(7011)8 i+ \1 Y; H4 {3 d5 z
  65. 5 J' k. @: e2 p; H4 V% T
  66. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
    : g" D9 @( g- a* h
  67. STARTED.addKillId(KELTIR_NPC_ID)  Q! r' D1 Y. N9 F2 n% O
  68. STARTED.addTalkId(7056)! u; B5 e) c! g1 M
  69. STARTED.addTalkI d(7012)
    3 S0 g% g. G0 l8 ]
  70. STARTED.addTalkId(7009)
    . o. {2 [+ c' I" {; T
  71. STARTED.addTalkId(7011)
Скопировать код
( b# K$ X0 S- F% Z7 _  z7 |7 G
6 Y. W) b7 J# O: e& c





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