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

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

Автор: admin    Время: 2024-9-17 19:36
Название: Создаём собственные квесты (часть 2)
Хроники        Interlude
4 D. f. K, Y! G1 `# A% a, ZСборка        L2j
  ]3 E. j" v9 s" EОбратите внимание: в файле htm стартового NCP обязательно должна быть ссылка на квест:
- l5 e- a% L* {" x( ]* j
  1. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста:1 m* P1 O4 m+ s* E; Q" Z
5 P5 t: _) J4 `8 s/ \
  1. if getCount(st) >= 4 :8 [: ~. |& N" q! P5 m% a
  2. completed(st)
    6 u' I  _! p: i4 b" h
  3.   return
    3 {% s, s( Z# l  T+ F
  4. 7 B( O$ n& f; B* A" D: A
  5. class Quest (JQuest):
    $ q' n5 b7 ~6 o3 H4 i4 {
  6.   def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)
    ! r8 R  ?: V& _, ~' o7 V& w. Z6 G
  7.   def onEvent (self,event,st):
    % h+ Q: t9 r/ i. u, {5 R% k, }
  8. id = st.getState()% D  n5 j2 w" ^8 x
  9. if   id == CREATED  : st.setState(STARTED)0 D" K" N) q3 s( T
  10. elif id == COMPLETED: pass
    1 v2 i, N) p) u* P% M! @2 T
  11. elif id == STARTED  : check(st)
    : R) d8 q$ I$ J8 Y% [
  12. return2 J5 X, S; ?# R& b% }

  13. $ t7 G' k) a: c. p8 f% n! h
  14. QUEST     = Quest(201,"Tutorial", "Tutorial quest")
    " K0 K1 v! u$ |8 [* e& r; b) F' L
  15. CREATED   = State('Start',     QUEST)
    $ `1 M$ J) L6 g9 C" m. P" O
  16. STARTED   = State('Started',   QUEST)- p* r4 ?2 R* K0 D
  17. COMPLETED = State('Completed', QUEST)' B# W' E$ u) ^+ `$ v2 X3 d, a( T
  18. ) s. O# p2 }6 C4 [/ |% F
  19. QUEST.setInitialState(CREATED)
    + s0 |5 m: _3 Y) v- j# ?. J
  20. QUEST.addStartNpc(7056)
    % ^2 [9 ?7 j7 c
  21. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Теперь рассмотрим, как это работает.
/ I! d8 y  o5 q$ J+ JИгрок подходит к начальному NCP (в данном случае 7056), нажимает на «Quest». Квест будет создан и состояние квеста перейдет к CREATED и игроку будет показана страничка Start.htm с описанием квеста. Тогда метод onEvent, поле открытия странички Start.htm переведет состояние квеста в STARTED и игроку будет показана страничка Started.htm, где будет опсание того, как найти keltirs и .т.д.6 {$ C; a8 y" q

! X) n3 [7 U+ X6 h3 X3 o

2 Y/ p' z6 ]; o0 `При состоянии STARTED будет зарегистрирован дроп «fangs» при убийстве keltirs. Игрок может вернуться к стартовому NCP и спросить о квесте – метод onEvent будет вызван снова. Если у игрока не хватает необходимого количества предметов, то метод check() не переведет квест в следующее состояние и Started.htm будет показана снова. Но если игрок собрал необходимее количество предметов (в данном случае 4 клыка), то метод check() вызовет метод completed() который переведет квест в новое состояние COMPLETED, заберет все клыки, даст карту мира, т.к. это награда за квест, покажет Completed.htm и завершит квест.* _8 d/ n7 E! F1 z( g

. r, V3 j/ C# {0 }7 O, M5 E

5 Z' h/ J9 z- oТеперь давайте сделаем наш квест более похожим на то, что он должен из себя представлять.
6 U" o" p4 \: zПрежде всего у нас есть 3 метода для объявления их в Яве – onTalk, onKill и onEvent. Если методы onTalk и onKill не объявлены, то за них все будет делать метод onEvent, т.е. определять квестовых монстров и вызывать диалоги NCP. Есть примечание, методы onTalk и onKill будут вызывать только диалоги с NCP в зависимости от текущего состояния квеста. Метод onKill будет вызываться только тогда, когда мы убиваем квестового монстра.) z+ T' s5 r4 Q3 d: Y
+ S/ z$ v: t+ H) L% _# D8 c( H

0 i0 p' q  ~) g- j$ v/ B/ S3 eДавайте рассмотрим как вызывается метод onKill при убийстве keltir в состоянии квеста STARTED:- X$ I8 W. T$ t* `5 E$ Q
  1. STARTED.addKillId(KELTIR_NPC_ID)
Скопировать код
и метод onKill в классе Quest:
! n. V3 A# d- O
4 p! ]" }% h: ^
  1. class Quest (JQuest):/ }9 }# X2 i; b. @6 u4 \
  2.   ...
    . j- q8 O8 f8 i+ Q
  3.   def onKill (self,npcId,st):
    * v4 Q3 \) ?0 q7 V% I
  4. if npcId == KELTIR_NPC_ID:4 a: g; _' y8 z0 s5 J2 {
  5.    n = getCount(st)
    4 f* i1 U8 B% ]' W& x) i
  6.    if   n == 0:7 @" D/ {2 @4 c7 e1 R
  7.        return "Chat0.htm"
    ' T" ~% u! K; q9 _# h+ N3 _( K" w; N$ Q
  8.    elif n == 1:3 b' ?" ~  Z" W& D2 J- E4 ]2 _
  9.        return "Chat1.htm"
    8 L/ r, ]% h& j) K
  10.    elif n >= 4:
    - N1 z: I2 A7 m; D+ V
  11.        return "Chat4.htm"3 Y% Y' J  }9 {
  12.    return "Collected "+str(n)+" of 4 fangs"% H% x8 R0 B3 D, B
  13. return
Скопировать код
Метод onKill (а так же метод onTalk) имеет следующие параметры:
  ]5 F7 M  t" z8 W" ~, R# X; T
6 C, X% @0 w+ B* |9 n# H
• self – квест
  p5 `9 J* B! \& A& E1 m• npcId – ID NCP, которого мы должны убивать (если это метод onTalk, то ID того NCP, с которым мы должны поговорить).
( [3 }' A2 J2 \• st – текущее состояние игрока.9 {3 Q0 M8 L7 w% R
) J! ^9 q6 v, u0 a, d4 w
. R8 M* r+ g- b: o& u
В этом методе мы проверяем и отмечаем, является ли убитый NCP keltir’ом. В основном эта проверка не нужна, т.к. у нас только KELTIR_NPC_ID.
0 t; L, E1 U2 `2 _
; @  n4 {8 G% H: Z1 Y3 s
* p  j9 ^. ^( k
Затем проверяем количество предметов (в данном случае количество клыков), и если их вообще нет, то возвращаем строку "Chat0.htm", если только один предмет, то возвращаем строку "Chat1.htm", если же предметов 4 или больше, то "Chat4.htm". Если строка возвращена из методов onEvent, onKill или onTalk, то сервер покажет соответствующие htm. В Chat0.htm может иметь следующий текст: «Вы не имеете ни одного клыка, возвращайтесь позже, когда соберете 4 штуки и бла, бла, бла…», в Chat1.htm может быть следующий текст: «У Вас всего 1 клык, по этому соберите еще…». В Chat4.htm – «Вы собрали необходимое количество предметов, возвращайтесь к вашему тренеру, что бы завершить квест…»
+ U. j" @% }2 v. f, Q  V( G2 p! _; K% x# K6 z* s2 W

- D) u: Y  j6 M- yПримечание: если в строка return начинается с "<html>", то будет показана страничка html с текстом, который стоит далее. Так вместо:( F+ ]' m. L( b4 g3 L
return "Chat4.htm"' r. e5 t& J" L- n7 D

% {9 @; t- u9 C
9 W( K; n: X) F8 ]( t. X
можно поставить:
  G) Y4 t% ?, ^
  1. return "<html><body>Return to your trainer to complete the quest</body></html>"
Скопировать код
Так же если строка заканчивается без .htm или в начале нет <html>, то текст будет выведен, как системное сообщение в окне чата. В нашем случае мы сделаем так, что бы при каждом убийстве keltik выводилось системное сообщение: «Собрано N из 4-х клыков».2 w4 T! e1 u0 m& _* [

/ V" R' D4 S" g/ G: y% Q
0 p3 c. T4 E% ]3 V
Наш код для onKill имеет один недостаток. Он будет постоянно показывать Chat0.htm, Chat1.htm и Chat4.htm, нам же необходимо, что бы Chat0.htm и Chat1.htm показывались только один раз. Как нам это сделать? С помощью переменных., ?5 F9 G$ R( h% \4 M
; R& E$ r( S* S/ a& t

6 K( ^- r- `8 ~8 H! W% [В каждом квесте строки могут храниться с помощью переменных. Эти переменные сохраняются в Вашей БД. В каждом методе мы можем назначить, прочитать и удалить переменные. Давайте изменим метод onKill, так что бы каждый диалог вызывался только один раз., s* y" M& z5 O5 x
  1. def onKill (self,npcId,st):" c; q3 S4 k0 s& X! j
  2. if npcId == KELTIR_NPC_ID:
    8 b$ m/ }$ r! U8 w& v) u0 M# k% q
  3. n = getCount(st)# o+ o) a- y# I: C! _& T
  4. if n == 0:
    6 t" |# D4 h. p
  5. if st.get('chat0') == None :9 Y/ e) _4 X) Y2 ?5 v3 X, I
  6. st.set("chat0", "true")
    9 b: j% L# v! z5 m" N: a2 Z$ [
  7. return "Chat0.htm"
    ' ^. G$ B( m4 r7 o
  8. elif n == 1:5 T! h" A* W/ P
  9. if st.get('chat1') == None :
    ; c: Q+ e2 t, @6 V& I5 e. p+ \
  10. st.set("chat1", "true")
    ; q# _( Q9 G1 \2 ?9 Y$ U
  11. return "Chat1.htm"
    3 L3 W# K2 r  {, x* Z. d
  12. elif n >= 4:/ R! r1 W. `4 M
  13. return "Chat4.htm"/ m4 s3 r( X  }) g- n, v
  14. return "Collected "+str(n)+" of 4 fangs"
    9 O9 H; i; j/ L% [& k$ y/ A% |
  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.
# O- T) w1 C# n% j/ z5 _! o
+ l! e4 W6 {7 z$ T$ I4 y
# Q; H2 W3 ]% I. }, h2 p+ ?4 ^
Вот конечный рабочий вариант квеста:
! V% {% |) M8 }8 D
  1. import sys" g. ]  ]4 [5 C# k9 w" ^0 c# f
  2. from net.sf.l2j.gameserver.model.quest import State2 n: a! L3 b7 H, r  m6 N& c$ [( Z
  3. from net.sf.l2j.gameserver.model.quest import QuestState: V7 H. F6 T# Q/ s; [; J2 H8 |
  4. from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest' `6 F8 {2 \  l

  5. & b( G9 L& v3 w) P
  6. KELTIR_NPC_ID = 120822 T, k4 h$ Q3 l% k
  7. FANGS_ITEM_ID = 1859
    # u* E8 u( n. ?/ C+ f( q  t
  8. DROP_RATE    = 5000003 q  V. V$ z" y" M" ^. N( e
  9. + a1 m  P+ N( l$ K9 |& `
  10. WORLD_MAP_ITEM_ID = 1665/ F1 C" S: e5 D% [7 T( X! g$ i

  11. ; L# _7 @$ L* Q& ^/ W: d5 o; r
  12. def getCount(st) :4 L( G+ i' o% F: A. F0 i! J
  13. return st.getQuestItemsCount(FANGS_ITEM_ID)
    5 A4 b' W8 v% X& b) @7 }/ n

  14. + t7 a' w3 g, ?, N5 B
  15. def completed(st) :
    % X2 }( L2 K" e1 Q
  16. st.setState(COMPLETED)4 ], y( e* |* p/ `
  17. st.clearQuestDrops()2 p, d" D! M$ p8 c' r: {/ |
  18. st.takeItems(FANGS_ITEM_ID,-1)
    ! O' t( Y% C( \1 @# B1 G8 e
  19. st.giveItems(WORLD_MAP_ITEM_ID,1)
    . h( M* t$ n9 X& b% Q$ }
  20. st.exitQuest(False)$ g" x# H$ b7 C7 O
  21. return  U; n0 Z4 q# n' P

  22. . t) O; D- m# t8 I1 h. Y( k0 I" K
  23. def check(st) :6 E5 t2 u# K) z1 g3 Y& T4 I9 r
  24. if getCount(st) >= 4 :
    : b- c, M  y  f8 T
  25. completed(st)8 z0 _" P) C1 c. }
  26. return
    5 _. g  }( B* G' X( K% ]/ C
  27. + O4 J6 Q+ j; s& V1 B+ G
  28. class Quest (JQuest):
    # \! |7 E1 p6 ?* e8 p% I8 |: t

  29. + D( o6 G8 y/ g& N+ B
  30. def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)% ?1 N; M: z) Z5 d/ ^4 G& |
  31. - _- b1 V. F0 }' d1 y2 w
  32. def onEvent (self,event,st):
    6 R( ~9 X( n# x& L
  33. id = st.getState()
    ( E" ]" G" B! g; v
  34. if id == CREATED : st.setState(STARTED)4 p: T8 Q1 @# W* R) @$ v
  35. elif id == COMPLETED: pass) b3 b1 S9 z# W' R6 W- \  U
  36. elif id == STARTED : check(st)8 y" C7 J6 k* Q, Q+ B  }* x0 h# u
  37. return0 @: X% E4 ?8 l* Y. j/ Q% F: D' d
  38. 9 g: H1 c* _/ R* Q4 ]+ t
  39. def onKill (self,npcId,st):
    7 N7 {0 U/ H6 A/ u6 |0 o
  40. if npcId == KELTIR_NPC_ID:
    " t: [. b6 [; `1 x: |
  41. n = getCount(st)  A8 g0 l5 T( Y+ @" j
  42. if n == 0:
    ) I8 \9 ^* C* L; ]
  43. if st.get('chat0') == None :5 `' r. U( ]6 }; b3 H+ M) ]
  44. st.set("chat0", "true")
    : l! B3 U+ F6 t; m( _
  45. return "Chat0.htm"
    4 _" Y: I  \0 ~& E% Q
  46. elif n == 1:0 k9 r7 o1 B& j4 K
  47. if st.get('chat1') == None :
    6 T3 A; I, L8 U4 T8 Z% q
  48. st.set("chat1", "true")
    ( F: W/ Z  T% g- d6 d" E
  49. return "Chat1.htm"8 p0 [/ v- {5 b8 F6 \
  50. elif n >= 4:: L7 \+ B+ _% k# ?
  51. return "Chat4.htm"
    2 @: I; K& T- f/ l! W
  52. return "Collect "+str(n)+" of 4 fangs"
    ' |; \5 l! U2 V0 o+ d
  53. return
    . M  p* |$ I4 i  q5 t) x5 J

  54.   B8 X! x( u7 U4 X% }
  55. QUEST    = Quest(201, "Tutorial", "Tutorial quest")
    4 Y" U6 W* P( S. Z% _
  56. CREATED = State('Start',    QUEST)
    $ P9 U% E) O0 [$ V# ^# ~
  57. STARTED = State('Started', QUEST)3 l) R7 M! [0 c, V! n" s
  58. COMPLETED = State('Completed', QUEST)
    : |; O% `  q9 [, Q% y
  59. : C8 \8 h% Q! W! N6 p* j7 j/ m
  60. QUEST.setInitialState(CREATED): T, q+ e/ L6 Q& o: Q2 Z$ v
  61. QUEST.addStartNpc(7056)
    % ^# F8 S9 w, h6 D+ E9 o& X& Y
  62. QUEST.addStartNpc(7012)
    : M0 X: J- j1 V* c
  63. QUEST.addStartNpc(7009)$ ]8 b  k, _* G- I; O' o
  64. QUEST.addStartNpc(7011)$ C, a% W; {# i( i
  65. % \/ O9 r0 L( N9 A& O, B: s
  66. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE), P2 ~0 y: Q1 V+ O: T
  67. STARTED.addKillId(KELTIR_NPC_ID)3 y* e8 x2 m' _3 c
  68. STARTED.addTalkId(7056)
    5 a4 ~0 o9 v' \. u0 R& Z) Y
  69. STARTED.addTalkI d(7012)* ^% W' D* E( `+ |# {6 h
  70. STARTED.addTalkId(7009)( p: f) v- `" U* `
  71. STARTED.addTalkId(7011)
Скопировать код
/ E' i, Q7 m! ?  i
" O  X: y# W" t6 N, T' m





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