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

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

Автор: admin    Время: 2024-9-17 19:36
Название: Создаём собственные квесты (часть 2)
Хроники        Interlude
3 v7 w! K! I2 I: i6 F! eСборка        L2j
8 n. Q6 Q/ W7 @* z' p! QОбратите внимание: в файле htm стартового NCP обязательно должна быть ссылка на квест:5 J( b! K3 {. Y" Q9 E: \
  1. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста:
" H) B- Y1 p' G/ H& M
  q! e1 i% J2 Q- a/ ^* S
  1. if getCount(st) >= 4 :
    " b7 @* W8 ], n/ ?9 o! B+ b
  2. completed(st)- {9 V3 o, A4 o: Q/ ~& O
  3.   return
    % Y! K- O' J3 n. P! I, \3 x3 ~3 G6 M

  4. # J7 P8 C" q6 q/ S* r
  5. class Quest (JQuest):
    5 o/ I8 C4 O, Q! \6 E4 u' f' P  e
  6.   def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr), P8 V8 D2 i% B( `
  7.   def onEvent (self,event,st):. C0 O* o- c  a/ M# u
  8. id = st.getState()" h/ p) x* ]5 u: b
  9. if   id == CREATED  : st.setState(STARTED)
    5 }' Q9 V+ J$ V. g  `
  10. elif id == COMPLETED: pass
    - a2 V/ T# c# w2 }8 p
  11. elif id == STARTED  : check(st)
    ' h6 ^8 R* G, `% N  S* J! S: @
  12. return2 y4 a, s; p3 f7 B6 g
  13. 1 g; k' ^9 d/ ^3 k5 M& t& R; H/ S# j+ J
  14. QUEST     = Quest(201,"Tutorial", "Tutorial quest")
    6 u* @$ f% r+ j  X- u8 T* H0 z
  15. CREATED   = State('Start',     QUEST)
    3 [3 |9 x" T- [7 j% J
  16. STARTED   = State('Started',   QUEST)
    / ~  R" K( E6 @5 m
  17. COMPLETED = State('Completed', QUEST)
    7 e* h; p+ L0 W' T$ z% G

  18. 7 Y, @: P9 s( T0 b4 Z+ u7 x
  19. QUEST.setInitialState(CREATED)+ C7 h  k3 U. F4 I- w" u7 p
  20. QUEST.addStartNpc(7056)/ r3 [  I0 K6 Q& a) T+ L
  21. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Теперь рассмотрим, как это работает.( v' y) e: ]/ {- k
Игрок подходит к начальному NCP (в данном случае 7056), нажимает на «Quest». Квест будет создан и состояние квеста перейдет к CREATED и игроку будет показана страничка Start.htm с описанием квеста. Тогда метод onEvent, поле открытия странички Start.htm переведет состояние квеста в STARTED и игроку будет показана страничка Started.htm, где будет опсание того, как найти keltirs и .т.д.
( R, s% M0 H; [3 Q8 a: s2 p
4 M5 ~! b5 I/ `, T4 x
- k' v  P; E0 q0 q  b$ d% s
При состоянии STARTED будет зарегистрирован дроп «fangs» при убийстве keltirs. Игрок может вернуться к стартовому NCP и спросить о квесте – метод onEvent будет вызван снова. Если у игрока не хватает необходимого количества предметов, то метод check() не переведет квест в следующее состояние и Started.htm будет показана снова. Но если игрок собрал необходимее количество предметов (в данном случае 4 клыка), то метод check() вызовет метод completed() который переведет квест в новое состояние COMPLETED, заберет все клыки, даст карту мира, т.к. это награда за квест, покажет Completed.htm и завершит квест.: d# d: `6 Q9 o5 ?
, D& k! M# w7 m- e2 ~

& B. H+ E# a4 c  D6 I1 xТеперь давайте сделаем наш квест более похожим на то, что он должен из себя представлять.
/ r6 W: b' ?3 v$ |3 m- UПрежде всего у нас есть 3 метода для объявления их в Яве – onTalk, onKill и onEvent. Если методы onTalk и onKill не объявлены, то за них все будет делать метод onEvent, т.е. определять квестовых монстров и вызывать диалоги NCP. Есть примечание, методы onTalk и onKill будут вызывать только диалоги с NCP в зависимости от текущего состояния квеста. Метод onKill будет вызываться только тогда, когда мы убиваем квестового монстра.
( U# B* I, R! f; Z& C- \
$ W2 b4 W, ^" V3 e; E) h

0 E5 R7 |3 s' Z# K8 FДавайте рассмотрим как вызывается метод onKill при убийстве keltir в состоянии квеста STARTED:1 ~4 U) }" R3 O6 B( o
  1. STARTED.addKillId(KELTIR_NPC_ID)
Скопировать код
и метод onKill в классе Quest:
9 ~* U& Z( M9 ?/ Z' m4 f, c3 M- {3 c8 f" |# u' Q
  1. class Quest (JQuest):
    ) o& ^. I( ~) f# s
  2.   ...9 b0 I# ^! d6 R3 ]- }* U5 O5 F
  3.   def onKill (self,npcId,st):7 G; V9 F7 S9 j5 Y
  4. if npcId == KELTIR_NPC_ID:
    4 z1 F( _7 J% E: e' \1 T
  5.    n = getCount(st)5 B7 l3 d, H1 P4 s; N/ N
  6.    if   n == 0:7 X8 }7 I8 j, _2 B
  7.        return "Chat0.htm"$ X8 O- H1 ~5 n: Q" |5 T+ Z
  8.    elif n == 1:5 X1 `4 V8 u( Q. I
  9.        return "Chat1.htm". Y  {6 K- F- ~1 z( r! {8 Y: V
  10.    elif n >= 4:( ~0 {( n  i, h# V
  11.        return "Chat4.htm"
    0 m  l# N2 ]3 q, e, d) b2 N& o7 Z
  12.    return "Collected "+str(n)+" of 4 fangs"1 k: I0 Z$ g6 S4 D
  13. return
Скопировать код
Метод onKill (а так же метод onTalk) имеет следующие параметры:
- i0 @) r; @3 {# m; |  O& @1 Y) p$ S% K
/ d5 D% ]# |" w6 N) s: J
• self – квест# W, R+ T8 Z' g# a- r! n* T6 N1 S
• npcId – ID NCP, которого мы должны убивать (если это метод onTalk, то ID того NCP, с которым мы должны поговорить).
# d: r% _, z5 R2 }2 U; E  p' v• st – текущее состояние игрока.3 ~6 V0 M4 j$ h) m; F* S
/ P. X$ l) f2 H" C+ q6 r8 y
& @$ W: H( p/ O6 e4 Y
В этом методе мы проверяем и отмечаем, является ли убитый NCP keltir’ом. В основном эта проверка не нужна, т.к. у нас только KELTIR_NPC_ID.
; F. s- Q7 A' w7 Y3 M- m
) p( I, B) S7 Z

3 d; U( f/ _2 j. g3 _Затем проверяем количество предметов (в данном случае количество клыков), и если их вообще нет, то возвращаем строку "Chat0.htm", если только один предмет, то возвращаем строку "Chat1.htm", если же предметов 4 или больше, то "Chat4.htm". Если строка возвращена из методов onEvent, onKill или onTalk, то сервер покажет соответствующие htm. В Chat0.htm может иметь следующий текст: «Вы не имеете ни одного клыка, возвращайтесь позже, когда соберете 4 штуки и бла, бла, бла…», в Chat1.htm может быть следующий текст: «У Вас всего 1 клык, по этому соберите еще…». В Chat4.htm – «Вы собрали необходимое количество предметов, возвращайтесь к вашему тренеру, что бы завершить квест…»& j; G9 X+ k' g2 a3 K2 y/ c

  B" c. @) a  y9 g, W
- M& K5 Q' U. }7 h4 ^! ^
Примечание: если в строка return начинается с "<html>", то будет показана страничка html с текстом, который стоит далее. Так вместо:
3 |2 ~9 B( m$ U0 E) ireturn "Chat4.htm"
2 h# {& Q1 D4 n! @2 v: `# U. q( J+ p
' n; n; s- o& t
можно поставить:
& S7 p4 q# y( q, M
  1. return "<html><body>Return to your trainer to complete the quest</body></html>"
Скопировать код
Так же если строка заканчивается без .htm или в начале нет <html>, то текст будет выведен, как системное сообщение в окне чата. В нашем случае мы сделаем так, что бы при каждом убийстве keltik выводилось системное сообщение: «Собрано N из 4-х клыков».
2 |9 e( b) I3 z( Z6 {
1 T/ D" d$ P( A" T( C

6 A7 z, m7 M  T$ ]4 bНаш код для onKill имеет один недостаток. Он будет постоянно показывать Chat0.htm, Chat1.htm и Chat4.htm, нам же необходимо, что бы Chat0.htm и Chat1.htm показывались только один раз. Как нам это сделать? С помощью переменных.; `$ o: S% v# F" _" V" t& p
4 o* h4 `% v# u. g8 }( g/ j5 q2 p, O

) F& N& Q/ X: CВ каждом квесте строки могут храниться с помощью переменных. Эти переменные сохраняются в Вашей БД. В каждом методе мы можем назначить, прочитать и удалить переменные. Давайте изменим метод onKill, так что бы каждый диалог вызывался только один раз.
" Y1 F% P2 I: \
  1. def onKill (self,npcId,st):
    & P8 ^4 S; a: V. f; K& W
  2. if npcId == KELTIR_NPC_ID:4 t$ t/ k8 d1 X. P. J
  3. n = getCount(st)1 \4 j6 j; m9 ?
  4. if n == 0:
    / K# o. h) T# y2 y1 Y
  5. if st.get('chat0') == None :5 U, z# ~. |( |8 }! }
  6. st.set("chat0", "true")  {  w$ N+ n& N7 i+ f. t
  7. return "Chat0.htm"
      f2 K3 U/ }' S& ?
  8. elif n == 1:9 P, S, L* L; M+ ?" _& ]2 ^- y
  9. if st.get('chat1') == None :
    $ ~  U: s) L; S# r- k+ j
  10. st.set("chat1", "true")
      ~8 {9 a( J% M3 ?1 \
  11. return "Chat1.htm"
    2 j/ w& n, _" l( `4 ^& X
  12. elif n >= 4:
    ' G  u0 _! H, n5 Q
  13. return "Chat4.htm"
    $ R4 {2 T: v" [" d- y9 q6 s
  14. return "Collected "+str(n)+" of 4 fangs"
    ; N6 Q) ~! p5 Y: Q4 E
  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.
- J" d) t1 g- R! ?7 o! F( {! P7 z9 z1 j* v
( m) d( w4 T2 }* I0 B- V
Вот конечный рабочий вариант квеста:
& h. L8 P. L1 U' Y( u
  1. import sys. v! c6 b7 W6 M0 q; K. Q
  2. from net.sf.l2j.gameserver.model.quest import State
    - V) q4 M1 \8 h) @
  3. from net.sf.l2j.gameserver.model.quest import QuestState% s% m3 w* s! X
  4. from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest
    6 ^7 q' W" b5 r' s" s3 A
  5. 0 d5 F: @' F& S) x2 D
  6. KELTIR_NPC_ID = 12082
    / W( l. t) |: d% ]
  7. FANGS_ITEM_ID = 1859' A5 E  h. g5 D& i' \2 V' t
  8. DROP_RATE    = 500000
    + ~( _; C0 Q0 w2 b: L* k

  9. 4 l3 d$ q" D: a! a/ b( f) F7 d* x) N3 `" {
  10. WORLD_MAP_ITEM_ID = 1665) ]! {  P1 D' T- {( U" P4 G( j, I

  11. 6 X: l9 j: j: }7 E; K" c$ p- o1 ~, V
  12. def getCount(st) :
    7 h2 l2 E$ A/ o& E4 g' n$ q
  13. return st.getQuestItemsCount(FANGS_ITEM_ID)9 f  s" x* d5 ~$ O9 @/ Z* b( ^, h
  14. $ ~* |/ O+ s4 V$ A7 t
  15. def completed(st) :  E" k; g1 G$ k) O  q  H( D
  16. st.setState(COMPLETED)3 O  P7 L3 y5 |6 K3 G5 w
  17. st.clearQuestDrops()# s5 F7 v* f% x0 G) r
  18. st.takeItems(FANGS_ITEM_ID,-1)2 y6 u( d! C) Z, a
  19. st.giveItems(WORLD_MAP_ITEM_ID,1)
    & f. q8 O* w# m3 U9 }% O3 c
  20. st.exitQuest(False)9 ~" n# s% P* ]+ y
  21. return. _, t. L: ~6 w0 r& v2 N

  22. * B- E$ ~9 W; L* O' d- K* z
  23. def check(st) :
    , @- c" X# H9 F8 n
  24. if getCount(st) >= 4 :( q6 h; f/ t" ?
  25. completed(st)
    + [+ z* e5 x2 k  H
  26. return
    ; x1 T+ C/ {8 H( e
  27. : i4 Z0 Y% z5 B# q( @* p
  28. class Quest (JQuest):
    ) k" Y0 G$ }1 {+ I  A# g

  29. ) C+ c4 v# l$ E  }
  30. def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)
    ! u: @5 b4 G( Q' O4 f

  31. ) l+ I  \5 J6 n
  32. def onEvent (self,event,st):
    6 M2 d0 ?% T$ B; L0 a
  33. id = st.getState(). z8 ?! o3 C* M1 r+ Q
  34. if id == CREATED : st.setState(STARTED)6 B3 g. T  N9 W% X' l8 A
  35. elif id == COMPLETED: pass
    ) q- j9 M# V6 q
  36. elif id == STARTED : check(st)! o9 }$ c0 b1 ^' U8 t3 f
  37. return. H! J6 V" M2 ~6 v2 Q1 Y: h

  38. ; t* n6 x: g2 d$ _7 C
  39. def onKill (self,npcId,st):
    $ A. w4 ?, X* K  ~+ k4 A4 V
  40. if npcId == KELTIR_NPC_ID:
    " S+ l" n( t! M
  41. n = getCount(st)# A) l% \# `& v
  42. if n == 0:" x9 G+ b- M8 x+ H+ t
  43. if st.get('chat0') == None :
    2 M: w; |! _4 q2 h
  44. st.set("chat0", "true")
    ) v' {3 Y& f! p# ]! ~
  45. return "Chat0.htm"
    ( }6 j' b$ |' I1 X* s# i# X
  46. elif n == 1:
    0 c) I# b. T* I( Z# C' a
  47. if st.get('chat1') == None :* F: g1 c  ^3 D4 h) Z
  48. st.set("chat1", "true")
    9 v7 O6 i  X% K5 l) ~3 F
  49. return "Chat1.htm"
    ( b% ?9 y0 y7 P# w, s
  50. elif n >= 4:# I2 S& W# g% L6 h5 q& @  K  X2 j0 R
  51. return "Chat4.htm"
    8 e3 S: }- c9 c. \; U
  52. return "Collect "+str(n)+" of 4 fangs"/ V- c/ M0 T1 X* L0 w) z1 E
  53. return: I5 ^: p5 k% C4 q  @
  54. " }+ |  g: u. J, t
  55. QUEST    = Quest(201, "Tutorial", "Tutorial quest")6 F1 [+ h+ C) S: `
  56. CREATED = State('Start',    QUEST)9 u" i# [; n# k2 A  _+ o& W
  57. STARTED = State('Started', QUEST)
    * l, z' B* t/ e- f/ k) N9 W, V
  58. COMPLETED = State('Completed', QUEST)
    ( E7 I, A6 U: z' o% X( y  a
  59. , P8 J+ E/ A* j5 g
  60. QUEST.setInitialState(CREATED)
    . K- e* J# c3 ~3 G
  61. QUEST.addStartNpc(7056)
    ' T- e" Y: f% Z
  62. QUEST.addStartNpc(7012). F: N1 v6 z- l& M8 G/ h8 R, n) T
  63. QUEST.addStartNpc(7009)) C+ N$ |+ o. Y7 u
  64. QUEST.addStartNpc(7011)
    . n  I6 {. i, f- D! l+ K

  65. + p# U- t& H; ~; o
  66. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
    2 \3 g7 X( R, d4 z" q
  67. STARTED.addKillId(KELTIR_NPC_ID). o; Y9 F( ~# |7 I4 V
  68. STARTED.addTalkId(7056)% k9 @) O2 C! M2 @# Y6 y# p
  69. STARTED.addTalkI d(7012)# ?$ p) f; |0 s( I; j
  70. STARTED.addTalkId(7009)7 u5 N: b9 j7 G4 |' t  s, v" m! `
  71. STARTED.addTalkId(7011)
Скопировать код
& A9 J) [) @% z# A& i: |, O7 j) r/ N
0 F( ?# H7 c4 W( I





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