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

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

Автор: admin    Время: 2024-9-17 19:36
Название: Создаём собственные квесты (часть 2)
Хроники        Interlude% e) x- G7 Y  i- O+ g1 j( h; o
Сборка        L2j
: M4 R3 |5 O8 qОбратите внимание: в файле htm стартового NCP обязательно должна быть ссылка на квест:# B% e1 N6 C: E3 N, Q, q
  1. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста:% N' g$ k: j- B

  T, Y' _) y' J$ a
  1. if getCount(st) >= 4 :
    + y- b/ [/ _1 y3 [& b7 f) _
  2. completed(st)
    3 G4 l" f6 g! q; k6 z  b
  3.   return
    5 \6 W0 s) I# Q4 W# u. x0 G+ P
  4. 4 l3 B& L4 j! F# p8 K0 d& J& i, X/ o8 c
  5. class Quest (JQuest):: N, ^1 e& j( l$ a5 |; p
  6.   def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)& ]- W. k( L% t9 w
  7.   def onEvent (self,event,st):3 Q, D3 k5 O( G% r6 M7 X; u
  8. id = st.getState()
    4 W5 _; q- r; s2 ]8 g6 l. M
  9. if   id == CREATED  : st.setState(STARTED)* i& W( I# b! e! x
  10. elif id == COMPLETED: pass) \7 ^0 C" L, N0 n5 k
  11. elif id == STARTED  : check(st)
    ) e1 w5 [4 ?9 K6 k4 ]; G
  12. return* i4 a) Q6 Q2 N7 j8 E' _% w
  13. / d( s: [- y' u6 c% z6 }
  14. QUEST     = Quest(201,"Tutorial", "Tutorial quest")7 ?" v, t: r; ], p+ T
  15. CREATED   = State('Start',     QUEST)  d# S  n2 G8 z& E/ j+ x7 F* n
  16. STARTED   = State('Started',   QUEST)
    ) g' |. X" u0 M2 I
  17. COMPLETED = State('Completed', QUEST)( p3 n" v  B4 }) s

  18. 2 g3 H; E9 ]2 j1 N8 L4 v
  19. QUEST.setInitialState(CREATED)$ [" Q8 O6 l! k! ]6 v5 ^  q# f! l
  20. QUEST.addStartNpc(7056)+ R. _& _2 ~4 w9 B$ H5 \8 V
  21. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Теперь рассмотрим, как это работает.  ^. e" Y, Z$ X+ Z/ y/ t) t
Игрок подходит к начальному NCP (в данном случае 7056), нажимает на «Quest». Квест будет создан и состояние квеста перейдет к CREATED и игроку будет показана страничка Start.htm с описанием квеста. Тогда метод onEvent, поле открытия странички Start.htm переведет состояние квеста в STARTED и игроку будет показана страничка Started.htm, где будет опсание того, как найти keltirs и .т.д.5 ?3 G6 Q$ V8 r
1 h- i3 n9 O( s- v
/ F9 A( G6 s9 @. F' s+ s/ b
При состоянии STARTED будет зарегистрирован дроп «fangs» при убийстве keltirs. Игрок может вернуться к стартовому NCP и спросить о квесте – метод onEvent будет вызван снова. Если у игрока не хватает необходимого количества предметов, то метод check() не переведет квест в следующее состояние и Started.htm будет показана снова. Но если игрок собрал необходимее количество предметов (в данном случае 4 клыка), то метод check() вызовет метод completed() который переведет квест в новое состояние COMPLETED, заберет все клыки, даст карту мира, т.к. это награда за квест, покажет Completed.htm и завершит квест.
4 v: N( O4 ]5 t
: l- F7 l5 T) J0 X
7 P4 [6 E- {" {( l% m# m" s/ }
Теперь давайте сделаем наш квест более похожим на то, что он должен из себя представлять.
  ~9 I- \8 {# u0 H7 f  E% cПрежде всего у нас есть 3 метода для объявления их в Яве – onTalk, onKill и onEvent. Если методы onTalk и onKill не объявлены, то за них все будет делать метод onEvent, т.е. определять квестовых монстров и вызывать диалоги NCP. Есть примечание, методы onTalk и onKill будут вызывать только диалоги с NCP в зависимости от текущего состояния квеста. Метод onKill будет вызываться только тогда, когда мы убиваем квестового монстра.$ Y$ [0 @+ V4 r+ l& W

- a1 W9 F. z6 Y& H, X, c" R. `: Z

6 C( w+ n! o5 L8 v  d" _5 TДавайте рассмотрим как вызывается метод onKill при убийстве keltir в состоянии квеста STARTED:( e& X! M$ |% }. B
  1. STARTED.addKillId(KELTIR_NPC_ID)
Скопировать код
и метод onKill в классе Quest:
/ u: j" N) p9 z
" B0 d8 X9 I- Q1 N- B+ T9 Y
  1. class Quest (JQuest):
    / y# n! ]5 M3 ~6 H6 B% D. b
  2.   ...
    " y: t2 D0 u$ n) L7 g- `0 C
  3.   def onKill (self,npcId,st):* z$ L) F/ Z* g1 _" c
  4. if npcId == KELTIR_NPC_ID:
    ( b; q+ D! c6 i
  5.    n = getCount(st)
    : D0 Y- m6 N/ _& R% G: @9 ]
  6.    if   n == 0:9 D* _! V0 f$ f+ y
  7.        return "Chat0.htm"
    6 y( x8 ]/ @2 {! d6 z3 E( b$ `
  8.    elif n == 1:8 n7 o6 A- w+ W, w
  9.        return "Chat1.htm"
    . a# Q. a, ]  F
  10.    elif n >= 4:
    " u6 U; q1 F. C* O, ?
  11.        return "Chat4.htm"
    & ~* \. p0 @* C+ C. x
  12.    return "Collected "+str(n)+" of 4 fangs"% v; f7 C% d# U
  13. return
Скопировать код
Метод onKill (а так же метод onTalk) имеет следующие параметры:( x# J% W1 W2 i" S2 c

# B* t6 n1 c2 V$ }/ S

1 [+ q# {) S8 x2 Z5 K• self – квест8 F% t- `$ b( R8 r5 s$ w- [% p1 j
• npcId – ID NCP, которого мы должны убивать (если это метод onTalk, то ID того NCP, с которым мы должны поговорить).
  Y: ]) p. R2 \1 X7 z) L6 X• st – текущее состояние игрока.4 s: e7 M4 h( S9 r
8 n! W! |# p( ?8 u% q
, w2 b$ t! t- N
В этом методе мы проверяем и отмечаем, является ли убитый NCP keltir’ом. В основном эта проверка не нужна, т.к. у нас только KELTIR_NPC_ID.
9 g, i" v- \; @$ A7 }4 t, `
9 \5 ~! |# `9 _& |1 h! o

, h7 `0 g: R' s* r8 e3 B) V$ m7 }Затем проверяем количество предметов (в данном случае количество клыков), и если их вообще нет, то возвращаем строку "Chat0.htm", если только один предмет, то возвращаем строку "Chat1.htm", если же предметов 4 или больше, то "Chat4.htm". Если строка возвращена из методов onEvent, onKill или onTalk, то сервер покажет соответствующие htm. В Chat0.htm может иметь следующий текст: «Вы не имеете ни одного клыка, возвращайтесь позже, когда соберете 4 штуки и бла, бла, бла…», в Chat1.htm может быть следующий текст: «У Вас всего 1 клык, по этому соберите еще…». В Chat4.htm – «Вы собрали необходимое количество предметов, возвращайтесь к вашему тренеру, что бы завершить квест…». U1 a  y6 L7 I, F" x

3 q" @* p$ V$ p1 r+ f' R& a2 E7 V+ T* }

# M* l2 {: Y, t: R  IПримечание: если в строка return начинается с "<html>", то будет показана страничка html с текстом, который стоит далее. Так вместо:
  j: q4 w0 e6 L- G0 }$ J% ~6 Vreturn "Chat4.htm"
5 E$ M# F) A0 w
. \2 b! |5 k4 d$ M  M

4 k8 N, E; o$ m% d) Xможно поставить:' ]( _6 i& ^' [' |- D
  1. return "<html><body>Return to your trainer to complete the quest</body></html>"
Скопировать код
Так же если строка заканчивается без .htm или в начале нет <html>, то текст будет выведен, как системное сообщение в окне чата. В нашем случае мы сделаем так, что бы при каждом убийстве keltik выводилось системное сообщение: «Собрано N из 4-х клыков».( E1 D% ~0 }9 ]! a) Y6 g

- w& f, u, k( \& V5 ]1 F
3 g, c5 H3 ^' J7 L6 u& w0 J
Наш код для onKill имеет один недостаток. Он будет постоянно показывать Chat0.htm, Chat1.htm и Chat4.htm, нам же необходимо, что бы Chat0.htm и Chat1.htm показывались только один раз. Как нам это сделать? С помощью переменных.
  R8 Y0 B! k+ Q7 v) ?! R0 F1 O0 V+ Q) C" m8 }: _

: X. D% U* ?" _3 F( F" H3 D4 vВ каждом квесте строки могут храниться с помощью переменных. Эти переменные сохраняются в Вашей БД. В каждом методе мы можем назначить, прочитать и удалить переменные. Давайте изменим метод onKill, так что бы каждый диалог вызывался только один раз.7 L5 \* W2 `5 b3 H
  1. def onKill (self,npcId,st):
    ; C) M) E2 @0 x9 c! y
  2. if npcId == KELTIR_NPC_ID:' t+ i9 i# e( m2 O2 e
  3. n = getCount(st)1 z, t9 Z* v  p3 m' j
  4. if n == 0:' P; g' I  D" P  C
  5. if st.get('chat0') == None :
    7 }- ?) l1 v% d" `
  6. st.set("chat0", "true")
    / Z1 S0 L# _# p$ W  P
  7. return "Chat0.htm"% {2 Q# `& ?- O9 v; h* Q' D
  8. elif n == 1:9 H+ h9 I- ]- X3 [
  9. if st.get('chat1') == None :# c" Z" }- I* }4 i& V+ T
  10. st.set("chat1", "true")- h; y" I; _: ~1 l; r
  11. return "Chat1.htm"
    . ^5 h) r! b! f. h7 q# {! u
  12. elif n >= 4:! C* t, V8 r0 {
  13. return "Chat4.htm"
    - z& H1 z7 ]' }3 M4 r2 N+ ?! Q
  14. return "Collected "+str(n)+" of 4 fangs"
    ' B* G; y: f3 }& V. b8 R
  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.
% H6 t* \% O. l6 ?  a8 J* W: |4 R" Z, W/ D* e2 t

' r; \7 o/ i, w: P' S1 pВот конечный рабочий вариант квеста:  {5 N/ e6 R+ s; H6 p$ R
  1. import sys0 I' |  d' S% c( K
  2. from net.sf.l2j.gameserver.model.quest import State9 q7 i% Y# E) p( B
  3. from net.sf.l2j.gameserver.model.quest import QuestState
    , w( M* H1 x( V" W% \
  4. from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest
    4 _& F6 M! z4 }" i2 m! W8 |( K

  5.   D6 D5 A6 c4 i/ |8 z# }
  6. KELTIR_NPC_ID = 12082+ B, ]0 k$ l& A5 o! B) `( e
  7. FANGS_ITEM_ID = 1859" Z" h# p7 g6 @5 r0 _
  8. DROP_RATE    = 500000
    2 k( l. p8 d$ r' _* z. j1 Q! |

  9. 0 o9 W; |5 s0 W% V
  10. WORLD_MAP_ITEM_ID = 1665
    0 G+ ~4 |& F8 `# A' J

  11. , l  g) e2 }, y' n
  12. def getCount(st) :
    7 ?: x. r% \9 }+ t) w4 S% H' N: D
  13. return st.getQuestItemsCount(FANGS_ITEM_ID)4 J  o: l3 B& f) `7 n1 a4 D
  14.   x5 V( _  |7 r: _" X
  15. def completed(st) :$ l6 Z+ T2 I8 s7 }# [1 k
  16. st.setState(COMPLETED)
    & l  q! C/ w6 U; J% {' q) h
  17. st.clearQuestDrops()
    ! @' r# v! L; e% L9 I" b
  18. st.takeItems(FANGS_ITEM_ID,-1), _, R8 U$ ?2 s# K( _
  19. st.giveItems(WORLD_MAP_ITEM_ID,1)& R5 A: t2 s" B1 S; S, b
  20. st.exitQuest(False)
    ) k$ Z( \* `1 h9 y8 T. }
  21. return2 |: W. X; U, h. w5 s
  22. ) `7 C" \/ e& d1 l
  23. def check(st) :
    9 }/ u" Z6 r' N0 T3 C/ P6 [' j
  24. if getCount(st) >= 4 :$ a- Z$ v8 N* h" h) X
  25. completed(st)  E, {% c2 }9 P
  26. return' q& `0 `* k$ D7 u; u+ D

  27. 3 G9 a7 S3 K' Q" p& Y8 x( j6 F
  28. class Quest (JQuest):+ B% c, n+ w/ D+ s6 M( S

  29. $ g$ t: _7 M) @2 L# ^, x
  30. def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)
    . U4 @) |/ d4 A% Q8 B+ C+ z
  31. 9 q2 E# u& w+ O* i
  32. def onEvent (self,event,st):
    / I" I& {( F/ E; G
  33. id = st.getState()
    2 h0 n7 `  i' q+ T
  34. if id == CREATED : st.setState(STARTED)
    ) D9 `* A/ u& Q5 X
  35. elif id == COMPLETED: pass
    6 W% Q& l0 H9 X/ u
  36. elif id == STARTED : check(st), x8 C) }% i$ [* G+ `5 s6 T& Q: [
  37. return
    ' C% }, P8 i5 w/ M: Y

  38. ! W/ r0 i1 K" n# f
  39. def onKill (self,npcId,st):
    1 y& @  j: C# r# K
  40. if npcId == KELTIR_NPC_ID:
    5 g" \- ?7 j" u+ v8 M
  41. n = getCount(st)+ J- i( I1 u. E1 ]) |' o2 Z
  42. if n == 0:
    + J& c, K) p5 x; }0 y1 j1 ]
  43. if st.get('chat0') == None :6 ]6 Y+ J, x$ i- U6 ?  G% x* g
  44. st.set("chat0", "true")+ H1 z* `3 ^+ u
  45. return "Chat0.htm": F3 Y% w7 m* [( H- s1 H) x0 Z
  46. elif n == 1:3 D8 p6 L3 v( u
  47. if st.get('chat1') == None :
    . p3 e" x9 A6 \  t8 v& T
  48. st.set("chat1", "true")
    - I  B9 I" x) e) l9 n1 Q# x% x
  49. return "Chat1.htm": m7 U9 v# q" |0 y& y) L# b
  50. elif n >= 4:& E; t+ R& s! z0 r$ d  W
  51. return "Chat4.htm"
    2 p) O6 `$ p1 H7 s
  52. return "Collect "+str(n)+" of 4 fangs"
    ' J7 z, y% P# h/ x" m5 U+ F
  53. return. f* ^8 h, N( l! [; S

  54. . D. ~! M# P$ u$ [& [1 g8 |% m
  55. QUEST    = Quest(201, "Tutorial", "Tutorial quest")( ]+ R8 V1 q4 y
  56. CREATED = State('Start',    QUEST)
    - T8 Y! ]! P" w( N& Z% [! S( l
  57. STARTED = State('Started', QUEST): n$ H9 P2 O3 C) F2 Z, k9 h
  58. COMPLETED = State('Completed', QUEST)/ T. u- [* p. x; p
  59. 6 o# ^% _2 E; t; j
  60. QUEST.setInitialState(CREATED)
    0 v# r4 n, U2 I% y* j- |
  61. QUEST.addStartNpc(7056)8 s; q6 y: x( o# E* N7 w7 k
  62. QUEST.addStartNpc(7012)5 ]4 X: _5 i5 L2 b$ m! T% D
  63. QUEST.addStartNpc(7009); ]# g1 [0 N" _. S) p
  64. QUEST.addStartNpc(7011)
    6 j- g% W  ]3 _8 d( D" ~

  65. 5 z6 p% f8 Q4 ?4 N5 l
  66. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)$ f; d) q0 }+ {
  67. STARTED.addKillId(KELTIR_NPC_ID). n& }, K9 ]  n  w
  68. STARTED.addTalkId(7056)
    0 H, U' i! h, x) h1 F; T- @
  69. STARTED.addTalkI d(7012)( {! F0 N% Q0 j2 Y# G9 i; V
  70. STARTED.addTalkId(7009)8 e4 u" v0 v0 T# Q
  71. STARTED.addTalkId(7011)
Скопировать код

# g3 {' k/ i. q% L" {6 ]
9 Q+ o, |6 b' {0 m3 O




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