Top.Mail.Ru

[Квесты] Создаём собственные квесты (часть 2)

[Скопировать ссылку]
admin Опубликовано 2024-9-17 19:36:47 | Показать все сообщения |Режим чтения Распечатать Назад Вперед

Зарегистрируйтесь сейчас чтобы найти еще больше друзей, и получить полноценный доступ ко всем функциям сайта!

Для просмотра Вам необходимо авторизоваться Если Вы еще не зарегистрированы, перейдите по ссылке:Зарегистрироваться

x
Хроники        Interlude
  W  n- B, ^, t& aСборка        L2j
8 X" T1 v! Z' gОбратите внимание: в файле htm стартового NCP обязательно должна быть ссылка на квест:
- P4 W0 ^  R- ^' ^, d
  1. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста:
8 D( |( C) u" M& u' [+ f( Q* ~6 a5 Q4 b0 B7 s" c
  1. if getCount(st) >= 4 :; r% z1 x! ~8 [/ z8 u) w: D2 U
  2. completed(st)3 D7 [/ ?5 S1 G5 n0 b# N- _1 D
  3.   return3 }6 I( |* a" Z
  4. 6 n4 C- @0 X$ ?" f) q
  5. class Quest (JQuest):
    8 K$ L% p6 a7 n! m. D
  6.   def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)( y5 j2 l* I! ]) ~. [$ }& A
  7.   def onEvent (self,event,st):/ r. _9 O2 t: y8 V: M' b
  8. id = st.getState()
    " Q- ?/ Q, Z0 {# _7 h* I
  9. if   id == CREATED  : st.setState(STARTED)% q. P, I8 f: L. _+ a1 I
  10. elif id == COMPLETED: pass( D5 Q6 O) z7 z8 x! z2 }5 c
  11. elif id == STARTED  : check(st)/ l: j9 C1 g0 K# q+ B9 M8 j
  12. return; F- p* F5 l5 D7 x! x# h
  13. . q! y4 Y( O) H$ n! z4 x
  14. QUEST     = Quest(201,"Tutorial", "Tutorial quest")# h% {# L' B5 e  ?# |
  15. CREATED   = State('Start',     QUEST)
    - r" \# ]" Z- L, P' U4 H
  16. STARTED   = State('Started',   QUEST)
    3 L+ u" a( q, r
  17. COMPLETED = State('Completed', QUEST)
    ) @3 U; `& n$ C* ]) F+ q  s; s& F

  18. 1 f, a* |+ G% q: u7 z: E
  19. QUEST.setInitialState(CREATED)
    ' w6 e5 o  c8 Z  g
  20. QUEST.addStartNpc(7056)0 _( e4 C" A4 b" b* A
  21. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Теперь рассмотрим, как это работает.
3 T' ?- h7 A; JИгрок подходит к начальному NCP (в данном случае 7056), нажимает на «Quest». Квест будет создан и состояние квеста перейдет к CREATED и игроку будет показана страничка Start.htm с описанием квеста. Тогда метод onEvent, поле открытия странички Start.htm переведет состояние квеста в STARTED и игроку будет показана страничка Started.htm, где будет опсание того, как найти keltirs и .т.д.. h. W  l, A$ C( O4 c

% x. x9 }+ y% M) V
8 k/ {- R9 Y; `4 e$ O% ^
При состоянии STARTED будет зарегистрирован дроп «fangs» при убийстве keltirs. Игрок может вернуться к стартовому NCP и спросить о квесте – метод onEvent будет вызван снова. Если у игрока не хватает необходимого количества предметов, то метод check() не переведет квест в следующее состояние и Started.htm будет показана снова. Но если игрок собрал необходимее количество предметов (в данном случае 4 клыка), то метод check() вызовет метод completed() который переведет квест в новое состояние COMPLETED, заберет все клыки, даст карту мира, т.к. это награда за квест, покажет Completed.htm и завершит квест.( |+ B  G) A* \- w( F& C
1 G" i5 r! {! v
' I' {5 `: h: {0 E6 O+ ]
Теперь давайте сделаем наш квест более похожим на то, что он должен из себя представлять.
7 u4 \5 }+ L, P* ]7 ~& zПрежде всего у нас есть 3 метода для объявления их в Яве – onTalk, onKill и onEvent. Если методы onTalk и onKill не объявлены, то за них все будет делать метод onEvent, т.е. определять квестовых монстров и вызывать диалоги NCP. Есть примечание, методы onTalk и onKill будут вызывать только диалоги с NCP в зависимости от текущего состояния квеста. Метод onKill будет вызываться только тогда, когда мы убиваем квестового монстра.
7 q3 x; A; q6 b: a: Y
5 o# z1 L0 ?! g& d4 t; z% a! ?
9 n/ @* n0 k/ {" a& J/ A
Давайте рассмотрим как вызывается метод onKill при убийстве keltir в состоянии квеста STARTED:
5 J; n1 R7 t9 `  x
  1. STARTED.addKillId(KELTIR_NPC_ID)
Скопировать код
и метод onKill в классе Quest:9 K6 g4 _1 v  x) {  l- F
1 W/ b: Y; Y8 n, s5 \# z  ]
  1. class Quest (JQuest):
    . Z1 s% q3 I3 p
  2.   ..." H. [$ T0 G2 t
  3.   def onKill (self,npcId,st):! w) j- u( \! z* w0 ?
  4. if npcId == KELTIR_NPC_ID:
    3 x7 v( L' r, L' ]* _7 i
  5.    n = getCount(st)
    6 S) `2 G+ b: p( T
  6.    if   n == 0:" Q0 z) _& C3 ~
  7.        return "Chat0.htm"$ t% t: X! w  n: ?2 v" z- H% r1 q! b
  8.    elif n == 1:
    * M* W6 G1 }7 T; j+ V
  9.        return "Chat1.htm"
      `% f% g8 ^% {' o( Y, O$ M
  10.    elif n >= 4:
    % J+ M3 u/ I! W6 X' f% H
  11.        return "Chat4.htm"1 ^7 p3 {# a; y3 N9 f8 Z# X# }
  12.    return "Collected "+str(n)+" of 4 fangs"
    , t0 p6 {- C5 `' T8 m( Y, N
  13. return
Скопировать код
Метод onKill (а так же метод onTalk) имеет следующие параметры:8 }' P+ d, m  d# P0 X

. U! K  J1 K( @, z1 l
) Y6 s) E3 {6 c7 K" b+ C* k
• self – квест
) }( a$ M5 Q( M  T) e/ E• npcId – ID NCP, которого мы должны убивать (если это метод onTalk, то ID того NCP, с которым мы должны поговорить).& S1 n1 |/ M0 d" b6 W* P
• st – текущее состояние игрока.' I# b+ A, [( J! x0 R2 i
$ o- t2 @7 m! }( `7 N7 C1 i

+ J4 h' n  `% r. qВ этом методе мы проверяем и отмечаем, является ли убитый NCP keltir’ом. В основном эта проверка не нужна, т.к. у нас только KELTIR_NPC_ID.
4 a- M9 E" i+ ~% I' v% H! r. q& D+ O
6 O7 o( x. t# ^" q$ L; Z# H3 }
Затем проверяем количество предметов (в данном случае количество клыков), и если их вообще нет, то возвращаем строку "Chat0.htm", если только один предмет, то возвращаем строку "Chat1.htm", если же предметов 4 или больше, то "Chat4.htm". Если строка возвращена из методов onEvent, onKill или onTalk, то сервер покажет соответствующие htm. В Chat0.htm может иметь следующий текст: «Вы не имеете ни одного клыка, возвращайтесь позже, когда соберете 4 штуки и бла, бла, бла…», в Chat1.htm может быть следующий текст: «У Вас всего 1 клык, по этому соберите еще…». В Chat4.htm – «Вы собрали необходимое количество предметов, возвращайтесь к вашему тренеру, что бы завершить квест…»3 F' {  ?3 \6 k- @: V
0 r% q2 W3 K, N
( O5 E0 f8 k) X) N' q! X
Примечание: если в строка return начинается с "<html>", то будет показана страничка html с текстом, который стоит далее. Так вместо:
. |0 x9 q( k" Z  E) \0 _return "Chat4.htm"5 g( G  `3 |1 h' Y5 l6 g# P( @
; B- _1 m3 m' [6 z# W% [8 O- V

/ _' U3 j1 m2 Lможно поставить:) s2 Q& T  }5 |2 g
  1. return "<html><body>Return to your trainer to complete the quest</body></html>"
Скопировать код
Так же если строка заканчивается без .htm или в начале нет <html>, то текст будет выведен, как системное сообщение в окне чата. В нашем случае мы сделаем так, что бы при каждом убийстве keltik выводилось системное сообщение: «Собрано N из 4-х клыков».2 h3 s  W& A% A2 {( R# M
" w3 R7 d3 b9 M( q. y$ a& ~
5 W6 g1 ]3 P# [' m+ C$ z# |+ ^, E
Наш код для onKill имеет один недостаток. Он будет постоянно показывать Chat0.htm, Chat1.htm и Chat4.htm, нам же необходимо, что бы Chat0.htm и Chat1.htm показывались только один раз. Как нам это сделать? С помощью переменных.
* h& V7 _9 t+ I- \1 S- X* E1 l1 v+ T3 C2 Q0 t0 Y6 x( p
& d9 y* ~  \6 M6 d7 j2 N
В каждом квесте строки могут храниться с помощью переменных. Эти переменные сохраняются в Вашей БД. В каждом методе мы можем назначить, прочитать и удалить переменные. Давайте изменим метод onKill, так что бы каждый диалог вызывался только один раз.' q; i& P& g2 v" ^( o) X- F
  1. def onKill (self,npcId,st):
    * O7 v" {5 h8 S- s  t; |1 S
  2. if npcId == KELTIR_NPC_ID:
    1 x) W! `$ {/ o
  3. n = getCount(st)
    % ?  {$ Y9 X& R& R1 s8 q$ `7 w& k
  4. if n == 0:
    3 _) ]& m7 s  ~; F* d" e
  5. if st.get('chat0') == None :
    & ^! r. h: |# B1 z6 f# |7 N) O/ ?6 w
  6. st.set("chat0", "true")
    & H# y4 ^% K8 i4 Q  A5 T6 Q$ x
  7. return "Chat0.htm"
    ' [: B* F+ k* j1 Y) q: ~0 `: e
  8. elif n == 1:
    4 Y: X6 L0 ^6 k, P' E
  9. if st.get('chat1') == None :
    3 L4 v) Z- C' U. q" {
  10. st.set("chat1", "true")
    ) I5 k# C; M$ V1 {" v
  11. return "Chat1.htm"
    0 V& A) o+ I: c5 }# f/ A
  12. elif n >= 4:
    2 J0 q: v, E; ]5 c
  13. return "Chat4.htm"; |  s: P: J) B
  14. return "Collected "+str(n)+" of 4 fangs"8 T4 `  p9 S0 H) d" F7 S
  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 @/ y* |* U4 J0 r2 u# U
. z: U' s+ z4 s: I; I8 J$ i

& O& I6 P8 d3 r/ m* K- WВот конечный рабочий вариант квеста:' h) b- g) l- K
  1. import sys2 v' l3 v& ?1 s0 G3 ]+ n$ U! T) y
  2. from net.sf.l2j.gameserver.model.quest import State/ q! D! ]6 _4 Y7 g
  3. from net.sf.l2j.gameserver.model.quest import QuestState& t* I2 L) b0 l# I
  4. from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest+ p( ]' u2 a7 [0 \' i
  5. ( R8 C) p! k( [5 X+ }# w
  6. KELTIR_NPC_ID = 12082
    0 |5 L' W2 Y( b, R
  7. FANGS_ITEM_ID = 1859) m( R3 u# }" \2 \( C
  8. DROP_RATE    = 500000
    2 `8 r) M7 ]2 H
  9. 3 o- O) L6 r4 q- m
  10. WORLD_MAP_ITEM_ID = 1665- T: s2 [* Z5 L+ Q% X7 _
  11. 1 v) Q$ e$ ~3 S; Q& }1 U
  12. def getCount(st) :0 l& f  i& V' G
  13. return st.getQuestItemsCount(FANGS_ITEM_ID)
    5 b  @: P+ D  T9 [' C4 C# F9 k
  14. " A% V9 d3 P" H7 |  F- f
  15. def completed(st) :% [  W) r  h% _/ D' @5 X  l$ H
  16. st.setState(COMPLETED)* l3 p  Z8 g1 K: t. L; m' g* m: |
  17. st.clearQuestDrops()
    ; I+ A/ p) }$ R; g- X, f, {0 b) U
  18. st.takeItems(FANGS_ITEM_ID,-1)5 ~) \, l" `: s! |4 [/ I
  19. st.giveItems(WORLD_MAP_ITEM_ID,1)
    0 D2 |! R3 m- \+ |) J
  20. st.exitQuest(False)2 ?! R. x/ D- W, s6 q, T1 L- E  y
  21. return# N$ m- e. {7 ], Q, i4 N4 S, A

  22.   y' o, g* |: G) W) g
  23. def check(st) :% s0 N  U. m+ G
  24. if getCount(st) >= 4 :' `# b0 F6 W3 d) }: G
  25. completed(st)+ A  |$ ^2 S& U- S
  26. return
    0 X+ P/ C% j7 a5 F0 p3 v. t

  27. 0 [2 L9 k' z2 N8 u
  28. class Quest (JQuest):
    0 b% D, J. T& G  q

  29. ( b$ _% U. w7 M8 l$ a1 V7 }$ t, O
  30. def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)1 A+ R: _5 e: {9 R

  31. ! J, x$ S- ^. I$ E$ T; P" V
  32. def onEvent (self,event,st):
    - K; C% l+ u. ?: k7 y* g% s$ T
  33. id = st.getState()( z+ M& D5 q+ E0 n+ h# c) [0 V
  34. if id == CREATED : st.setState(STARTED)
    2 e  j1 e; E- U$ X0 ~0 |# |8 j
  35. elif id == COMPLETED: pass
    % ~7 {% I- C8 S
  36. elif id == STARTED : check(st)
    # j! P* k, p( I/ q" j$ r# S+ ~9 v
  37. return, z5 B$ o7 I' K  Q  H

  38. $ M. b& F  O; u3 a2 `
  39. def onKill (self,npcId,st):- `" [! m0 z' Q; V) r; w: I
  40. if npcId == KELTIR_NPC_ID:! f: n, I  z6 t! s/ z0 x$ u
  41. n = getCount(st)7 i0 ^4 q/ e( ~0 }) N* ~
  42. if n == 0:  V0 B1 O; S7 |& M
  43. if st.get('chat0') == None :
    7 z, _* r# x8 }6 C5 U, H# r8 Y* q' o$ X
  44. st.set("chat0", "true")
    . b- m& R& z. N+ L+ H9 k1 n
  45. return "Chat0.htm"
    0 H: e& S5 {3 d3 g' A4 y! j
  46. elif n == 1:: w" n5 \% n; V- i- ?
  47. if st.get('chat1') == None :: U$ u3 }/ E& T/ W  ^  B
  48. st.set("chat1", "true")5 X! c9 z/ u) w
  49. return "Chat1.htm"
    % `+ a5 f' r, B) U+ s8 M1 X
  50. elif n >= 4:% Y; A8 a$ j6 S2 s$ _# P8 @5 o( m
  51. return "Chat4.htm"; D  B( e8 d3 Q* g
  52. return "Collect "+str(n)+" of 4 fangs"
    8 L* Y6 P# n; v
  53. return
    % f5 Z% \, c3 J3 a
  54. ' X+ R/ |& H' f; [$ h" }, |
  55. QUEST    = Quest(201, "Tutorial", "Tutorial quest")+ s$ R3 s; s6 _. `
  56. CREATED = State('Start',    QUEST); ]0 ~7 Y' ?' H1 Z. x' n
  57. STARTED = State('Started', QUEST)
    + o  [: d) p& V2 w
  58. COMPLETED = State('Completed', QUEST)
      ^" G! e) C# y) J$ r) V+ ]
  59. 0 V0 l* x/ L# c- D, ~8 x
  60. QUEST.setInitialState(CREATED)
    3 Q) ~7 j( G# B3 z
  61. QUEST.addStartNpc(7056)
    ) C! j+ }5 t. U
  62. QUEST.addStartNpc(7012)$ m6 J2 K5 b! f) {: w, W
  63. QUEST.addStartNpc(7009)
    1 C+ Y  Y/ B* l! H
  64. QUEST.addStartNpc(7011)/ t. J0 C5 }+ @: G! J0 q

  65. ( p( s$ q0 k/ w; p  X& s
  66. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
    $ n8 x9 O% |. i- H
  67. STARTED.addKillId(KELTIR_NPC_ID)
    7 k; n/ |! [1 M, x: ^5 ]
  68. STARTED.addTalkId(7056)' _, Y2 U/ b$ x0 v; Z. i
  69. STARTED.addTalkI d(7012). ?) j, {" a9 S9 `8 `. ^' i
  70. STARTED.addTalkId(7009)
    * f0 A4 u5 ~9 I4 V8 Q
  71. STARTED.addTalkId(7011)
Скопировать код
: Q9 J' ~( @( N. k0 B# p' a2 y
6 n- G. D7 }1 O. Z
Чтобы ответить, вам надо авторизироваться в системе Вход | Зарегистрироваться

Правил начисления баллов

Опубликовать
Сектор творческих людей
Горячая линия

638638758

С понедельника по воскресенье с 9:00 до 23:00

Обратной связь

admin@artace.ru Онлайн

QR-код

Powered by Discuz! X3.5© 2001-2021 Comsenz Inc.