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

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

Автор: admin    Время: 2024-9-17 19:36
Название: Создаём собственные квесты (часть 2)
Хроники        Interlude( z7 _5 Q: j+ m$ \# C9 B+ v
Сборка        L2j
; j! a  [6 y2 x# N2 X) x4 rОбратите внимание: в файле htm стартового NCP обязательно должна быть ссылка на квест:6 ]$ `. U. l7 O$ G: J/ |
  1. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста:1 A  Z8 W) C: D$ ^% H" m

" p( p' V, d* R- |
  1. if getCount(st) >= 4 :* `6 ]; a  b7 K: @  o+ Z1 ?
  2. completed(st)# W# [# }% q2 c! q
  3.   return
    3 Q* a$ X5 L. S

  4. ( D, x  z5 x7 B6 S% v
  5. class Quest (JQuest):4 `  P  F+ X: R- @/ S7 d- i: k
  6.   def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)
    ! `$ Q$ O! P  j9 S
  7.   def onEvent (self,event,st):* G! b1 ~' ]" z& G
  8. id = st.getState()
    . T5 j* Y, ^: d3 ]4 D
  9. if   id == CREATED  : st.setState(STARTED)
    ; f7 m# z) o3 K
  10. elif id == COMPLETED: pass
    5 T8 s  ?$ N. R/ D4 D
  11. elif id == STARTED  : check(st)
    ) H" u: u# m' d
  12. return. l! J& @7 A+ i- e% e4 x

  13. 7 ~/ A' ^# h  `3 U( `
  14. QUEST     = Quest(201,"Tutorial", "Tutorial quest")
    $ }! S. P4 J  f
  15. CREATED   = State('Start',     QUEST)# u) s, \; c; L4 u* @) x
  16. STARTED   = State('Started',   QUEST)
    6 d& m7 K, Y' Q* x' s6 j
  17. COMPLETED = State('Completed', QUEST)
    ' q" [2 F2 K8 b/ A+ N0 w* k5 @( Y

  18. 9 U0 E: G  k1 f- W$ l
  19. QUEST.setInitialState(CREATED)+ T! n! C! x) ~- V  V4 k+ F
  20. QUEST.addStartNpc(7056)
    9 V0 g% `" k3 F' i2 S0 @% y6 T% A
  21. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Теперь рассмотрим, как это работает.
: \+ m, Q9 q$ a1 b" ^Игрок подходит к начальному NCP (в данном случае 7056), нажимает на «Quest». Квест будет создан и состояние квеста перейдет к CREATED и игроку будет показана страничка Start.htm с описанием квеста. Тогда метод onEvent, поле открытия странички Start.htm переведет состояние квеста в STARTED и игроку будет показана страничка Started.htm, где будет опсание того, как найти keltirs и .т.д.- Q- \9 ]  d9 A$ p! }! Q) ?
1 i3 ]- I+ m& \' b5 X
2 M- g. d% Q7 I7 B6 t+ D6 g- ^1 x
При состоянии STARTED будет зарегистрирован дроп «fangs» при убийстве keltirs. Игрок может вернуться к стартовому NCP и спросить о квесте – метод onEvent будет вызван снова. Если у игрока не хватает необходимого количества предметов, то метод check() не переведет квест в следующее состояние и Started.htm будет показана снова. Но если игрок собрал необходимее количество предметов (в данном случае 4 клыка), то метод check() вызовет метод completed() который переведет квест в новое состояние COMPLETED, заберет все клыки, даст карту мира, т.к. это награда за квест, покажет Completed.htm и завершит квест.; O3 f( l* \: Q% V
( A6 ^4 R$ q) E6 u& [
' q' q/ O. J# V$ V
Теперь давайте сделаем наш квест более похожим на то, что он должен из себя представлять.; S' L* i- B) R2 X) G% z9 V. @
Прежде всего у нас есть 3 метода для объявления их в Яве – onTalk, onKill и onEvent. Если методы onTalk и onKill не объявлены, то за них все будет делать метод onEvent, т.е. определять квестовых монстров и вызывать диалоги NCP. Есть примечание, методы onTalk и onKill будут вызывать только диалоги с NCP в зависимости от текущего состояния квеста. Метод onKill будет вызываться только тогда, когда мы убиваем квестового монстра.* D5 M( @' A' ], t9 M
' ?/ s$ d3 A% r3 G/ @

7 ], _4 `. v+ k) S9 x- N# sДавайте рассмотрим как вызывается метод onKill при убийстве keltir в состоянии квеста STARTED:5 b1 i$ j4 u1 k2 g$ x
  1. STARTED.addKillId(KELTIR_NPC_ID)
Скопировать код
и метод onKill в классе Quest:+ p% z; W% H( k& g( p: A
3 F1 k4 |% i7 A5 Y
  1. class Quest (JQuest):1 G, c2 Y4 s+ n& c3 [4 V- k
  2.   ...+ t# S! z. I5 m) f) G8 _+ v+ Z
  3.   def onKill (self,npcId,st):' m+ C% q+ y( N  H* q. {. n
  4. if npcId == KELTIR_NPC_ID:
    + r& b# Y1 N1 p) b9 ?3 u
  5.    n = getCount(st): N* p& l# t) d& w$ T+ L
  6.    if   n == 0:  W# c3 L6 e  _/ H) c" u
  7.        return "Chat0.htm": Q& L+ ]+ q6 P! }
  8.    elif n == 1:
    6 [6 ~+ Z. A- [
  9.        return "Chat1.htm"
    * I1 ^- V) h0 g
  10.    elif n >= 4:& x  C) q1 R6 Q) f
  11.        return "Chat4.htm", c: \& V1 v7 Y; U4 c- l3 l
  12.    return "Collected "+str(n)+" of 4 fangs"
    8 C$ g  {* O! q3 E7 U
  13. return
Скопировать код
Метод onKill (а так же метод onTalk) имеет следующие параметры:9 F& e3 H; g* [8 A

1 n( u! p8 Q& k3 `- o
6 G: Y& I8 v7 n& I4 ^1 }
• self – квест
5 O. [: I2 x" m( h- _4 U• npcId – ID NCP, которого мы должны убивать (если это метод onTalk, то ID того NCP, с которым мы должны поговорить).5 y/ j$ F7 O( Y# P  W4 |/ C
• st – текущее состояние игрока.
, o3 \9 _1 h9 C  |9 ^0 n% F  k, V' d0 P1 [
3 [: h; s! E4 y1 J- h% c
В этом методе мы проверяем и отмечаем, является ли убитый NCP keltir’ом. В основном эта проверка не нужна, т.к. у нас только KELTIR_NPC_ID.
- Q! ?. ^. l9 R& i- p+ H) [. o2 n

) {/ y+ `9 D! D2 K6 m" Q8 SЗатем проверяем количество предметов (в данном случае количество клыков), и если их вообще нет, то возвращаем строку "Chat0.htm", если только один предмет, то возвращаем строку "Chat1.htm", если же предметов 4 или больше, то "Chat4.htm". Если строка возвращена из методов onEvent, onKill или onTalk, то сервер покажет соответствующие htm. В Chat0.htm может иметь следующий текст: «Вы не имеете ни одного клыка, возвращайтесь позже, когда соберете 4 штуки и бла, бла, бла…», в Chat1.htm может быть следующий текст: «У Вас всего 1 клык, по этому соберите еще…». В Chat4.htm – «Вы собрали необходимое количество предметов, возвращайтесь к вашему тренеру, что бы завершить квест…»
0 h+ g, L1 @1 _5 @, A7 p& `- I; ]+ _1 j

: v% X8 @1 H3 a$ Y+ b1 p8 bПримечание: если в строка return начинается с "<html>", то будет показана страничка html с текстом, который стоит далее. Так вместо:
: M/ p: l0 r6 O: E# w/ ^return "Chat4.htm"
( k* B* Q) V' K# @$ A1 d4 e$ I, N
9 {$ ~& ^, h% M! z* X+ D# j

* Q8 W! V4 I2 Y7 @8 nможно поставить:
( L: O: U* C1 K7 k9 ]
  1. return "<html><body>Return to your trainer to complete the quest</body></html>"
Скопировать код
Так же если строка заканчивается без .htm или в начале нет <html>, то текст будет выведен, как системное сообщение в окне чата. В нашем случае мы сделаем так, что бы при каждом убийстве keltik выводилось системное сообщение: «Собрано N из 4-х клыков»., H; @% y* V+ p" U
1 T, Z  M8 w! d1 t9 I4 h

, f0 X' V& o. N7 d# M( p: `1 aНаш код для onKill имеет один недостаток. Он будет постоянно показывать Chat0.htm, Chat1.htm и Chat4.htm, нам же необходимо, что бы Chat0.htm и Chat1.htm показывались только один раз. Как нам это сделать? С помощью переменных.
1 ^7 ?$ Q* P* h( ~
! g, d! d& ]2 s- a0 S$ I+ L3 H
( r) n3 ~$ P! B3 a7 V
В каждом квесте строки могут храниться с помощью переменных. Эти переменные сохраняются в Вашей БД. В каждом методе мы можем назначить, прочитать и удалить переменные. Давайте изменим метод onKill, так что бы каждый диалог вызывался только один раз.. z: E3 u/ T' ]1 L; G, b
  1. def onKill (self,npcId,st):
    ( }: @; h3 n% D" A
  2. if npcId == KELTIR_NPC_ID:* }4 D- s2 y$ K5 F
  3. n = getCount(st)) S1 n. Y" x. m" `( R+ A. J- J
  4. if n == 0:
    4 J, z. x; Z2 K3 B9 m3 {+ c
  5. if st.get('chat0') == None :
    ; _: P: p% M: e6 [
  6. st.set("chat0", "true")
    + g; G* f. B! l7 g+ X
  7. return "Chat0.htm"
    5 Y+ ^* j1 e, @0 f  a; ^) ^
  8. elif n == 1:0 |$ g. R0 u" p: c/ q' T, n- z
  9. if st.get('chat1') == None :( y3 S' e% X2 a- x& y8 `4 l0 @" {
  10. st.set("chat1", "true")
    3 k1 f! Z7 E  _$ I' q
  11. return "Chat1.htm"
    & ?6 A: |0 L0 F5 e" x/ k
  12. elif n >= 4:- b4 L* ^- L7 x+ J7 B! S
  13. return "Chat4.htm"; ?0 S) E& k# ^
  14. return "Collected "+str(n)+" of 4 fangs"
    0 j5 |& u! \8 V4 U7 _. i, 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.
% h# a4 L6 X4 ]- E
$ U4 [6 ~! d5 I2 z3 u& g( |4 B) ]

4 _# S/ y8 q. D; Q/ |4 E3 R4 ^  s. fВот конечный рабочий вариант квеста:
0 G% \# Q: Q: [5 ^
  1. import sys
    % e" d4 Q# T" F5 E
  2. from net.sf.l2j.gameserver.model.quest import State
    3 g6 S, X9 l0 i$ u* U
  3. from net.sf.l2j.gameserver.model.quest import QuestState' g% e) S9 d& U2 P, K
  4. from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest3 z0 q. r1 U% I& D" c3 V( O

  5. 6 [* S' T2 h! O/ a3 J* d
  6. KELTIR_NPC_ID = 12082. `1 }% ~; S+ q* y: R% a( \# |/ N
  7. FANGS_ITEM_ID = 1859
    7 W! P; d" G; b- }5 n9 y: D
  8. DROP_RATE    = 500000$ j, J' G* |) k1 _; Y6 D

  9.   r; s" E) C# s( \7 b% r
  10. WORLD_MAP_ITEM_ID = 1665+ W/ C5 M  k/ Z
  11. & J/ v' g5 I% [, z* E* Y
  12. def getCount(st) :
    , c' z; Z" i; F: Y4 O. ^
  13. return st.getQuestItemsCount(FANGS_ITEM_ID)3 E- O' @' k& Q5 k
  14. " }  ?/ X9 z6 L0 l& Y. a% l
  15. def completed(st) :
    0 Z- W4 C) S! g# R, w
  16. st.setState(COMPLETED)
    3 p3 g* ^6 u- r' c# e4 l: Z, E  [! F6 j
  17. st.clearQuestDrops()
    ) Z% `/ y+ f* A, B' `
  18. st.takeItems(FANGS_ITEM_ID,-1)
    ' ?1 \/ d# j/ H2 x. Q% F
  19. st.giveItems(WORLD_MAP_ITEM_ID,1)6 Q: f0 n5 {- }9 O
  20. st.exitQuest(False)
    ) a3 e3 ~9 v% Z: O: W2 R5 M
  21. return
    ! [+ \/ T: R1 }! N0 W

  22. & T5 K+ e$ S# K9 |: [$ A* k
  23. def check(st) :- c9 c# j$ }) {% y
  24. if getCount(st) >= 4 :! \+ S% T4 b" ~' o
  25. completed(st)% O/ T# e+ \& N& `0 W
  26. return
    " R8 t3 B4 U# I+ c8 [

  27. # `% K7 Q" C6 `2 h/ W! m
  28. class Quest (JQuest):1 J" U4 }3 q# }+ r) r4 ~7 x8 x

  29. 6 m1 n. G3 }* V7 N. g- z
  30. def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)' m7 l( ]4 S& X! F8 r
  31. 9 i  ]3 Y8 o- _
  32. def onEvent (self,event,st):# S( P( ]  V" y1 G) p
  33. id = st.getState()1 y4 A; ?9 t+ ~7 ^6 I
  34. if id == CREATED : st.setState(STARTED)
    4 ]! |: _' [. l7 O' C  F
  35. elif id == COMPLETED: pass
    1 Y2 |* x7 @6 K. Q$ `: A9 v1 w
  36. elif id == STARTED : check(st)$ [! s( }+ P2 `0 O
  37. return8 U' C; ?8 O( P- P$ Z! m" e
  38. ( s4 M2 H2 P6 T4 w/ S9 s
  39. def onKill (self,npcId,st):
    6 g) Z0 k  p, I5 m0 n: l
  40. if npcId == KELTIR_NPC_ID:, S5 s& `7 m1 J. Z* `1 G, s
  41. n = getCount(st)
    ) R* A, l. M3 j& F6 o( S* \9 M
  42. if n == 0:4 T+ G0 F- J6 p
  43. if st.get('chat0') == None :( k. x7 ], P0 Z; {! T
  44. st.set("chat0", "true")
    ! U9 |) z" Y" _
  45. return "Chat0.htm"0 _6 H0 L( j5 x( |! r# X7 J& f
  46. elif n == 1:
    ! ~* K7 ]- Z5 c
  47. if st.get('chat1') == None :
    - N4 G' A8 p% F3 x0 F, b( v
  48. st.set("chat1", "true")( [, O& h3 M- d3 }, a
  49. return "Chat1.htm"
    0 l! m3 J8 W4 Q" L8 ^; p" A1 a8 A
  50. elif n >= 4:' P3 }, f$ K/ A- Q4 B
  51. return "Chat4.htm". W  F% i2 S* Y3 `: ]9 i1 G
  52. return "Collect "+str(n)+" of 4 fangs"
    ( N7 E6 p( T5 R% H' e( M
  53. return5 q' k: F& K$ M# h; k# k7 H5 c
  54. ' M/ G- g" b  G- }1 F8 T. `
  55. QUEST    = Quest(201, "Tutorial", "Tutorial quest")
    3 J* d! b/ J* J# w  Y+ r
  56. CREATED = State('Start',    QUEST)  X7 K  g+ z" L
  57. STARTED = State('Started', QUEST)
    8 Q1 c+ s8 h1 J8 E
  58. COMPLETED = State('Completed', QUEST)
    ( k" J' m/ n" ^( r9 t: C# u3 u
  59. 4 J. O0 N* d- N
  60. QUEST.setInitialState(CREATED)- s' @. x( f* A. v  }) E
  61. QUEST.addStartNpc(7056); d$ X, O$ O0 f/ _1 Q7 b) A
  62. QUEST.addStartNpc(7012)
    % G) @9 j( E  V
  63. QUEST.addStartNpc(7009)
    * e7 j8 k1 E( G$ h( C/ I
  64. QUEST.addStartNpc(7011)
    $ l% E* T7 ]" r6 w7 p( m
  65. 3 M7 {, C# w0 }& B: ~
  66. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)# V" N# S4 q8 @  J% b2 W8 Z
  67. STARTED.addKillId(KELTIR_NPC_ID)* ~% {/ J  Q3 F+ {
  68. STARTED.addTalkId(7056)3 S7 a3 l! J% N: j- c0 \6 ?
  69. STARTED.addTalkI d(7012)
    9 b: R/ j. m' n5 R  ?7 [* N
  70. STARTED.addTalkId(7009)
    9 y% f8 v. ^# Q  ~( \6 P
  71. STARTED.addTalkId(7011)
Скопировать код

5 M) `9 p! d1 m) P  m4 |
6 z6 @  g. U% C/ U




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