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

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

Автор: admin    Время: 2024-9-17 19:36
Название: Создаём собственные квесты (часть 2)
Хроники        Interlude( {$ n- K1 W6 Z( p2 W4 V  O# h
Сборка        L2j
0 q  y5 L" P/ R# W$ w  `Обратите внимание: в файле htm стартового NCP обязательно должна быть ссылка на квест:  `- @! d1 V) U4 @2 j" s& _
  1. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста:
$ Q& P# R+ \2 b
6 s  K1 Z' y: b9 R4 M$ a, h
  1. if getCount(st) >= 4 :0 T) p2 @3 b- R- v/ f+ s
  2. completed(st)
    1 Z! P7 I* f5 B% A# l
  3.   return& ~# O# }" d+ `" S0 h, s  F4 V( z( L
  4. - a: ~7 d9 h. Q! Z
  5. class Quest (JQuest):
    7 F7 U% r) z! {7 i: W) A) n
  6.   def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)
    $ R, |/ M" ]' ?5 o7 k* E& W
  7.   def onEvent (self,event,st):
    3 C) N" G+ t* F% O7 p+ U' q+ L
  8. id = st.getState()$ h  ^' Q! t# [- L" s. y& r
  9. if   id == CREATED  : st.setState(STARTED)
    # R2 W0 y% A: J: b! ^+ }
  10. elif id == COMPLETED: pass
    $ v9 L$ @$ C: y- b2 `7 L3 V' w
  11. elif id == STARTED  : check(st)# y4 l  x7 \- Q# ~
  12. return
    7 W; g' j: F6 q7 E; V- s2 Z+ ?

  13. ' P- r- L1 C3 L9 t! Q
  14. QUEST     = Quest(201,"Tutorial", "Tutorial quest")
    ' o) H8 ]" W, C* F
  15. CREATED   = State('Start',     QUEST)
    % D3 T$ f: _$ e( ~  @
  16. STARTED   = State('Started',   QUEST)
    1 N$ w, @  K; m  H1 Y# A6 t# y
  17. COMPLETED = State('Completed', QUEST)9 u0 O2 ?+ E: H5 e+ Y1 ^6 y/ w

  18. ' p; H4 h( Z/ N; g5 s
  19. QUEST.setInitialState(CREATED)
    ) Q6 H) X& J; @! X6 o( a3 f
  20. QUEST.addStartNpc(7056)
    3 ?. U8 ?8 z. W. Q  d$ _; ]( ]: Z
  21. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Теперь рассмотрим, как это работает.7 }; ?/ I1 b9 [3 E
Игрок подходит к начальному NCP (в данном случае 7056), нажимает на «Quest». Квест будет создан и состояние квеста перейдет к CREATED и игроку будет показана страничка Start.htm с описанием квеста. Тогда метод onEvent, поле открытия странички Start.htm переведет состояние квеста в STARTED и игроку будет показана страничка Started.htm, где будет опсание того, как найти keltirs и .т.д.1 F' k- i& p3 @' Q

3 W0 \0 f( J/ e$ Z, V1 A
8 |4 M; P1 c9 t4 D3 Z
При состоянии STARTED будет зарегистрирован дроп «fangs» при убийстве keltirs. Игрок может вернуться к стартовому NCP и спросить о квесте – метод onEvent будет вызван снова. Если у игрока не хватает необходимого количества предметов, то метод check() не переведет квест в следующее состояние и Started.htm будет показана снова. Но если игрок собрал необходимее количество предметов (в данном случае 4 клыка), то метод check() вызовет метод completed() который переведет квест в новое состояние COMPLETED, заберет все клыки, даст карту мира, т.к. это награда за квест, покажет Completed.htm и завершит квест.4 s! V0 L. p' _
  F7 o( l* @) S9 C/ |; \" l: a0 z
6 l; M# h( ]6 P0 F
Теперь давайте сделаем наш квест более похожим на то, что он должен из себя представлять., j+ b- X/ T! c4 z5 K7 b
Прежде всего у нас есть 3 метода для объявления их в Яве – onTalk, onKill и onEvent. Если методы onTalk и onKill не объявлены, то за них все будет делать метод onEvent, т.е. определять квестовых монстров и вызывать диалоги NCP. Есть примечание, методы onTalk и onKill будут вызывать только диалоги с NCP в зависимости от текущего состояния квеста. Метод onKill будет вызываться только тогда, когда мы убиваем квестового монстра.
" _0 t$ P' j; L( b6 k1 J
6 P2 Q4 b$ E8 F8 |
  V7 ^6 y2 G' E& X! {- p: o
Давайте рассмотрим как вызывается метод onKill при убийстве keltir в состоянии квеста STARTED:
+ f% Z* P# M7 m4 L
  1. STARTED.addKillId(KELTIR_NPC_ID)
Скопировать код
и метод onKill в классе Quest:
/ W  z) Z" k- f1 j* T1 i. {0 n" {: |, r0 _. x, o
  1. class Quest (JQuest):& G5 }8 e2 ?. n, u2 J+ a/ n) f
  2.   ...
    2 A- ~; o* R5 z
  3.   def onKill (self,npcId,st):
    ( ]3 D5 p* n" Q3 R, h
  4. if npcId == KELTIR_NPC_ID:
    ) W' b8 v0 t# [! ?
  5.    n = getCount(st)
    & i* R8 p% t$ m' h/ ~7 a6 R
  6.    if   n == 0:
    4 @( W- A# M2 D1 _, s
  7.        return "Chat0.htm"
    , k5 g+ P6 k: Y% F% _4 O6 s
  8.    elif n == 1:
      @1 V& u6 J. i% X
  9.        return "Chat1.htm"
    + b  l) `3 e$ m' T  X: H" J% V  y
  10.    elif n >= 4:
    1 o# B7 k. w7 B; ]5 V7 N0 j
  11.        return "Chat4.htm"
    ) G$ m( \9 F2 g1 x6 F
  12.    return "Collected "+str(n)+" of 4 fangs"( l. b' J! o1 a" O) h
  13. return
Скопировать код
Метод onKill (а так же метод onTalk) имеет следующие параметры:
4 G# E# T# G% Z7 b1 w
3 z7 L. a- a6 L. a8 Q" U! t
' `9 {0 n# ^; ]6 j" X* J
• self – квест
7 m8 J4 V- e& L! G• npcId – ID NCP, которого мы должны убивать (если это метод onTalk, то ID того NCP, с которым мы должны поговорить).# ?) _) i( P6 T& k: W
• st – текущее состояние игрока.4 q  @; h8 L/ i& ]" Z

8 S1 v" {) r4 M7 M) X; ?

' M# P. C" F6 M# V& {' lВ этом методе мы проверяем и отмечаем, является ли убитый NCP keltir’ом. В основном эта проверка не нужна, т.к. у нас только KELTIR_NPC_ID.* H  g6 H7 Z4 W1 I

. n: z* ?, Z$ I5 K) r- w
5 _. R" [% ^6 l4 y0 W
Затем проверяем количество предметов (в данном случае количество клыков), и если их вообще нет, то возвращаем строку "Chat0.htm", если только один предмет, то возвращаем строку "Chat1.htm", если же предметов 4 или больше, то "Chat4.htm". Если строка возвращена из методов onEvent, onKill или onTalk, то сервер покажет соответствующие htm. В Chat0.htm может иметь следующий текст: «Вы не имеете ни одного клыка, возвращайтесь позже, когда соберете 4 штуки и бла, бла, бла…», в Chat1.htm может быть следующий текст: «У Вас всего 1 клык, по этому соберите еще…». В Chat4.htm – «Вы собрали необходимое количество предметов, возвращайтесь к вашему тренеру, что бы завершить квест…»
7 \* ^8 S1 U3 q7 w1 e, r9 t6 I8 Y0 D) x; S

' k8 W; E+ U' @* B0 Q- L. h8 cПримечание: если в строка return начинается с "<html>", то будет показана страничка html с текстом, который стоит далее. Так вместо:
" F( D  [6 u7 e4 D9 T% l- k6 Nreturn "Chat4.htm"; d9 @1 u/ E& f: e5 t' R

% F% s/ Q6 n% ~3 W- ~( T) C

/ {& p) ^& k& J8 n& l  t# t, U) cможно поставить:# H/ ~, L; \+ I( I- h
  1. return "<html><body>Return to your trainer to complete the quest</body></html>"
Скопировать код
Так же если строка заканчивается без .htm или в начале нет <html>, то текст будет выведен, как системное сообщение в окне чата. В нашем случае мы сделаем так, что бы при каждом убийстве keltik выводилось системное сообщение: «Собрано N из 4-х клыков».# W& O7 `8 U/ e( _/ c! l
9 z% U6 [% C7 r, }" V
0 Z( Y7 s7 r4 g$ t6 b
Наш код для onKill имеет один недостаток. Он будет постоянно показывать Chat0.htm, Chat1.htm и Chat4.htm, нам же необходимо, что бы Chat0.htm и Chat1.htm показывались только один раз. Как нам это сделать? С помощью переменных.0 w1 X2 f0 _5 y( Q& ]' ]
# \9 `: S6 G" H
6 |7 G$ x$ u3 ^9 b5 e1 G, `: x! k5 f
В каждом квесте строки могут храниться с помощью переменных. Эти переменные сохраняются в Вашей БД. В каждом методе мы можем назначить, прочитать и удалить переменные. Давайте изменим метод onKill, так что бы каждый диалог вызывался только один раз.& d2 f4 ~0 U& z  B- g
  1. def onKill (self,npcId,st):) I2 A' C" I3 k4 x( E
  2. if npcId == KELTIR_NPC_ID:
    0 E8 K5 x6 y% h5 l+ G$ |  v+ c
  3. n = getCount(st)
    4 F. @% N4 }  M2 t6 T6 N" U
  4. if n == 0:
    ( c. ?9 D2 a# B& S; C2 T- y
  5. if st.get('chat0') == None :
    0 b! O, Q: `; D) t) g3 L1 t
  6. st.set("chat0", "true")
    7 Q: m; r8 V) k( x
  7. return "Chat0.htm"& \& G- \: D4 V; `9 p3 A' E
  8. elif n == 1:" }* W1 M) k9 `) ]. E: H! q9 u
  9. if st.get('chat1') == None :
    $ x, E5 W/ `9 y5 ^
  10. st.set("chat1", "true")# f$ C- L6 J5 l1 r+ ]" m9 i- N- k
  11. return "Chat1.htm"; f( O" c" L6 V) \$ e  i) I2 V# l7 n
  12. elif n >= 4:4 f1 {5 S3 E* G0 w( Z$ }/ C
  13. return "Chat4.htm"+ `8 `& V, y& P, \- \2 N  K2 Z
  14. return "Collected "+str(n)+" of 4 fangs"% [% h* J  C6 g$ H: E  @5 D
  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 P9 d/ N9 j* v9 W, b6 a

, V- i' l0 ?. M8 a& b- V

8 v4 p1 H6 s; G' ^* e  W3 I7 wВот конечный рабочий вариант квеста:
2 y- y2 I$ c5 }( G# b
  1. import sys4 s; t7 F- {* h
  2. from net.sf.l2j.gameserver.model.quest import State* N5 q8 z  e( @2 {. V& \
  3. from net.sf.l2j.gameserver.model.quest import QuestState$ f' c4 S5 X& R& o+ e0 j6 l/ H, }
  4. from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest
    7 U: s1 X5 W4 }" o' G0 I

  5. # O" v* K$ J* a- L! {0 ~6 K: G
  6. KELTIR_NPC_ID = 12082
    # r7 u2 p3 Y2 A# O* I& t6 i
  7. FANGS_ITEM_ID = 1859
    6 O2 ^; _& S5 y2 Y0 Z! C
  8. DROP_RATE    = 500000& B. Q& S) q- C+ g, \
  9. 0 a( @2 o7 G8 f+ Y( [; ]
  10. WORLD_MAP_ITEM_ID = 1665: r+ H+ B0 o6 ?, t, i' B  ~
  11. / e& P- w* w" s' v) t" w
  12. def getCount(st) :
    $ o+ P; f( s+ Q; g  D0 N4 k$ j
  13. return st.getQuestItemsCount(FANGS_ITEM_ID)
    9 [4 ?6 ?4 N! R/ E  s+ M
  14. - Q+ N; d5 {# {, [* t$ {* X/ g6 P
  15. def completed(st) :, j! G3 J4 g2 J7 P. O
  16. st.setState(COMPLETED): |" c! J% ~9 G6 ]% }# f9 K" v2 I
  17. st.clearQuestDrops()
    " X$ K  U* O/ @8 i- C
  18. st.takeItems(FANGS_ITEM_ID,-1)
    : m0 t: s8 S& H$ J( h
  19. st.giveItems(WORLD_MAP_ITEM_ID,1)# \  W; ?+ o8 D  j! W- E
  20. st.exitQuest(False)
    . s* Y* S$ ~8 g% z: I  ]/ z  |1 A
  21. return' O1 K8 K! [+ R, q
  22. + w; Y7 s& v- Y; G; @2 ]8 @
  23. def check(st) :
    # b0 }: ]6 c7 R- g
  24. if getCount(st) >= 4 :- L% ?( w8 c7 T0 N
  25. completed(st)
    0 p: ?% r' y- [  k' K) G/ }
  26. return8 `, J2 L6 p6 }$ m6 S( F3 E) n8 I

  27. ' v; V/ n* g2 A( o/ b
  28. class Quest (JQuest):  l6 W, e" P6 N8 \( k2 g  o, H  _
  29. . e/ l5 j4 D% L/ K' f
  30. def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)
    4 k6 F: w4 K3 f( t, L# w

  31. $ h# J5 z6 S! |5 j
  32. def onEvent (self,event,st):$ M: P# P0 E* L: a4 F
  33. id = st.getState()1 t% p) x0 B5 r/ [) @
  34. if id == CREATED : st.setState(STARTED)4 j9 W0 o* @% w
  35. elif id == COMPLETED: pass' p) j$ q& K$ _2 E) X- J
  36. elif id == STARTED : check(st)
    & p. o5 X5 Z3 R
  37. return
    : t0 P5 o+ T) C* t
  38. , @' o3 d4 Y8 q" m2 f# K
  39. def onKill (self,npcId,st):
    ; h$ z3 ?- w: b3 t1 Q
  40. if npcId == KELTIR_NPC_ID:
    / ?- [0 g+ v0 `% y
  41. n = getCount(st)
    7 j% l4 G+ i1 d* F; J  C( P& K6 Y, y
  42. if n == 0:
    . M4 Z% U& [* i* t
  43. if st.get('chat0') == None :
    ; b% ?0 H# a$ _  ?
  44. st.set("chat0", "true")" H# W7 m7 Z+ E2 c
  45. return "Chat0.htm"$ |. Q0 J' }+ k7 ]  [. u8 C
  46. elif n == 1:8 W  h5 C/ J$ n: O
  47. if st.get('chat1') == None :
    ) M/ i1 K) i( f" d+ c# o1 s6 n
  48. st.set("chat1", "true")6 ^, h( J$ R/ l- x2 N! T
  49. return "Chat1.htm"8 V4 c+ V( g" ^/ W; T  A6 P
  50. elif n >= 4:
    * ^% Z  f  u1 Z3 X% g: x9 U* J, L
  51. return "Chat4.htm"' q9 Q8 }, W& ]# w: V6 @& ~
  52. return "Collect "+str(n)+" of 4 fangs"
    * w) t& k1 x, k# Q, I& \- J* H
  53. return) o- ~% i- p  g( v* Z; z
  54. - |6 e% c9 u2 d7 o& g* c4 e
  55. QUEST    = Quest(201, "Tutorial", "Tutorial quest")
    $ b5 n! T0 R! s
  56. CREATED = State('Start',    QUEST)
    & T5 |6 {5 I- N, T
  57. STARTED = State('Started', QUEST)# \0 A8 A. m+ Y# |
  58. COMPLETED = State('Completed', QUEST)
    & @! P/ Q$ O' R1 J
  59. ; `. K% \# z, ^6 Z& W% R1 F# k) Y
  60. QUEST.setInitialState(CREATED)$ R7 f: ?( J3 c: x' {) b
  61. QUEST.addStartNpc(7056)
    2 [/ D/ |3 v* v7 N+ [
  62. QUEST.addStartNpc(7012)( X7 ^" h- r! O5 E% D; k
  63. QUEST.addStartNpc(7009)
    2 K% g7 E8 O" I9 r( R
  64. QUEST.addStartNpc(7011). b: m) e( W6 w) e$ C! l
  65. 9 C/ F1 B% ~) e; M5 U( f' u
  66. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)8 f7 x; D( g* _3 |
  67. STARTED.addKillId(KELTIR_NPC_ID)
    # T2 p7 l* g' V* m# O& s4 D
  68. STARTED.addTalkId(7056), T. g- u, B/ u4 m7 x
  69. STARTED.addTalkI d(7012)
    " \* ?0 B0 X2 j5 Z; U
  70. STARTED.addTalkId(7009), O; Z& N0 P0 c9 {. `9 y7 E
  71. STARTED.addTalkId(7011)
Скопировать код

$ w3 H$ K1 c4 O' X
* z- ~. U0 W6 m  b& ~6 ], v: \




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