Top.Mail.Ru

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

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

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

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

x
Хроники        Interlude& M; J2 y; c0 h5 p  T# c
Сборка        L2j
) f5 U. T6 m( \9 z8 S/ _: ^Обратите внимание: в файле htm стартового NCP обязательно должна быть ссылка на квест:0 t$ X5 D9 a9 ^3 Q6 f) ^& h
  1. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста:' f" b8 S; K$ K  ^3 M

$ j" o/ X0 k0 m$ a8 `) o% z% `
  1. if getCount(st) >= 4 :
    . X3 O' ?& ]6 a  y' D
  2. completed(st)0 ?! t$ r. \# u' p
  3.   return  D7 B1 }5 U. G0 O. r% l
  4. - o, B* ~5 g9 w# ~4 L- D3 W
  5. class Quest (JQuest):/ \4 w$ o# s+ d& s* J5 E) g# t
  6.   def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)8 c# s) }. N2 p( R/ j
  7.   def onEvent (self,event,st):5 ?: ?% M) M# X: q7 A0 W! c
  8. id = st.getState(), `5 d. B, O/ M- k
  9. if   id == CREATED  : st.setState(STARTED)4 h% V- t; G4 B  R+ q
  10. elif id == COMPLETED: pass9 k) _8 g3 Y0 a' V2 E: h/ r
  11. elif id == STARTED  : check(st)
    & X' _" t# ]1 q" M  ~7 E7 X) C
  12. return
    & O& j7 r" ~2 W

  13. ! B- V! w% {. d9 U" f' p( h
  14. QUEST     = Quest(201,"Tutorial", "Tutorial quest")
    % z( @: L* v6 V9 M+ \
  15. CREATED   = State('Start',     QUEST)( v# Z+ M" K( W3 j
  16. STARTED   = State('Started',   QUEST)$ ?, X1 y1 q3 _) p0 _+ e
  17. COMPLETED = State('Completed', QUEST)
    : I# g9 w+ k: o

  18. , s  ^0 g, M4 x& B2 K7 [* v' z& R
  19. QUEST.setInitialState(CREATED)
    . d. \0 j0 u1 ?3 _& K
  20. QUEST.addStartNpc(7056)
    7 z/ e$ n- w  h3 r
  21. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Теперь рассмотрим, как это работает.  Q0 r/ o2 J/ ^: Q0 z
Игрок подходит к начальному NCP (в данном случае 7056), нажимает на «Quest». Квест будет создан и состояние квеста перейдет к CREATED и игроку будет показана страничка Start.htm с описанием квеста. Тогда метод onEvent, поле открытия странички Start.htm переведет состояние квеста в STARTED и игроку будет показана страничка Started.htm, где будет опсание того, как найти keltirs и .т.д.5 N3 f; d5 Z0 c. [3 d$ E& Z- k
/ {! k, T( ^+ U$ A% F

9 R, e. y+ }0 Y! GПри состоянии STARTED будет зарегистрирован дроп «fangs» при убийстве keltirs. Игрок может вернуться к стартовому NCP и спросить о квесте – метод onEvent будет вызван снова. Если у игрока не хватает необходимого количества предметов, то метод check() не переведет квест в следующее состояние и Started.htm будет показана снова. Но если игрок собрал необходимее количество предметов (в данном случае 4 клыка), то метод check() вызовет метод completed() который переведет квест в новое состояние COMPLETED, заберет все клыки, даст карту мира, т.к. это награда за квест, покажет Completed.htm и завершит квест.
8 x+ D9 k7 ~2 }: `; K% W3 a) `4 Z/ }' P3 Q. J) l8 p4 D
5 A& |  S9 v9 Z0 r
Теперь давайте сделаем наш квест более похожим на то, что он должен из себя представлять.
  O8 |( Q6 H$ w% ^4 bПрежде всего у нас есть 3 метода для объявления их в Яве – onTalk, onKill и onEvent. Если методы onTalk и onKill не объявлены, то за них все будет делать метод onEvent, т.е. определять квестовых монстров и вызывать диалоги NCP. Есть примечание, методы onTalk и onKill будут вызывать только диалоги с NCP в зависимости от текущего состояния квеста. Метод onKill будет вызываться только тогда, когда мы убиваем квестового монстра.
. q4 Q0 k: z) U7 W5 ]( R, l8 G* v* \* F# `
' h1 o$ f1 ~: S4 N* C
Давайте рассмотрим как вызывается метод onKill при убийстве keltir в состоянии квеста STARTED:" T# U8 U" a1 G$ k/ ~, {
  1. STARTED.addKillId(KELTIR_NPC_ID)
Скопировать код
и метод onKill в классе Quest:, a5 u% J3 w. m; ~, x- N

1 h2 e% {$ L7 C2 m" d+ @* H
  1. class Quest (JQuest):
    0 K0 D' R2 h; e! y/ I( }
  2.   ...) l- U# _- j! D) w$ o- H9 v
  3.   def onKill (self,npcId,st):, E# F6 ~- O% D; J" N
  4. if npcId == KELTIR_NPC_ID:
    ' h7 x- n) |$ n# E$ ?
  5.    n = getCount(st)
    ) G2 @9 @  g% r% p% C" C# V( ^5 O
  6.    if   n == 0:, |0 A( I/ w* a
  7.        return "Chat0.htm"# w. d+ c4 _7 L0 x0 D' U: G
  8.    elif n == 1:! A4 i0 E. b' R  H4 ~' d, h# u
  9.        return "Chat1.htm"
    + {) j  ^$ s" t/ z2 I7 V7 f
  10.    elif n >= 4:0 H9 b) z9 c% C: c
  11.        return "Chat4.htm". J# N) \. ]' V' D# {' b, R- e+ [
  12.    return "Collected "+str(n)+" of 4 fangs"+ }3 S+ R- Y* j& \
  13. return
Скопировать код
Метод onKill (а так же метод onTalk) имеет следующие параметры:' R/ _: v) w0 Y
# [# T- J  ?, Y3 m1 ^. I0 J

- Z+ D. Z6 m+ p) p. s% ^* V0 W6 y• self – квест
0 S; S  X8 e' }! c; ?• npcId – ID NCP, которого мы должны убивать (если это метод onTalk, то ID того NCP, с которым мы должны поговорить).
5 y+ d  S  v- P, T: V• st – текущее состояние игрока.
& D+ W8 ^- z. s" ^8 R
3 E! o8 ^" k. l" S7 W/ S! {' g
! i% d* d9 ~1 ?& `- F) E, p
В этом методе мы проверяем и отмечаем, является ли убитый NCP keltir’ом. В основном эта проверка не нужна, т.к. у нас только KELTIR_NPC_ID.8 H- s" l2 g" j7 @; z  S7 P

9 V3 P8 y" E& O
4 p0 B9 O& ^5 V% R8 o- P8 J* U
Затем проверяем количество предметов (в данном случае количество клыков), и если их вообще нет, то возвращаем строку "Chat0.htm", если только один предмет, то возвращаем строку "Chat1.htm", если же предметов 4 или больше, то "Chat4.htm". Если строка возвращена из методов onEvent, onKill или onTalk, то сервер покажет соответствующие htm. В Chat0.htm может иметь следующий текст: «Вы не имеете ни одного клыка, возвращайтесь позже, когда соберете 4 штуки и бла, бла, бла…», в Chat1.htm может быть следующий текст: «У Вас всего 1 клык, по этому соберите еще…». В Chat4.htm – «Вы собрали необходимое количество предметов, возвращайтесь к вашему тренеру, что бы завершить квест…»
# x$ p5 j8 U, B: o- r1 L2 r
4 p$ ]9 ^+ B1 q
, i: @5 K# r. C, K) P# T5 i
Примечание: если в строка return начинается с "<html>", то будет показана страничка html с текстом, который стоит далее. Так вместо:
; `3 v8 Q9 A3 C6 `return "Chat4.htm"
* v' g- e: I0 L! N* r% ^0 v* y) i0 B/ _. q1 V: P( `% F. K0 z  i# L

1 @5 Y5 x+ s  _# p2 M) Eможно поставить:
3 j" r  q  W5 e3 o3 R( f
  1. return "<html><body>Return to your trainer to complete the quest</body></html>"
Скопировать код
Так же если строка заканчивается без .htm или в начале нет <html>, то текст будет выведен, как системное сообщение в окне чата. В нашем случае мы сделаем так, что бы при каждом убийстве keltik выводилось системное сообщение: «Собрано N из 4-х клыков».
+ Z8 @' i, Q9 ?( a$ e! \4 X0 A0 K9 m( C! T4 A2 M. N! ?
5 `; @1 p" r$ K, e$ M) ?1 B
Наш код для onKill имеет один недостаток. Он будет постоянно показывать Chat0.htm, Chat1.htm и Chat4.htm, нам же необходимо, что бы Chat0.htm и Chat1.htm показывались только один раз. Как нам это сделать? С помощью переменных.8 T6 G4 f5 y- t9 F9 N6 u. B
3 ?8 E" A/ \, I" g  x

  U2 r5 _( c' H2 Y# t6 ~, @7 ^В каждом квесте строки могут храниться с помощью переменных. Эти переменные сохраняются в Вашей БД. В каждом методе мы можем назначить, прочитать и удалить переменные. Давайте изменим метод onKill, так что бы каждый диалог вызывался только один раз.
/ z$ N; e, A: K; C0 B% h
  1. def onKill (self,npcId,st):
    ! M  k- h4 l/ F: X; ~7 B# i7 s
  2. if npcId == KELTIR_NPC_ID:  O) U8 h! H. _1 f
  3. n = getCount(st)
    ! Y! F* {; E$ I2 g
  4. if n == 0:: a& f% a4 v+ B# P& w
  5. if st.get('chat0') == None :
    7 _3 ~6 F) F) U. R8 b8 \
  6. st.set("chat0", "true")
    3 D7 @' M: z" Y& y0 h, H6 N
  7. return "Chat0.htm"1 S" A1 J6 u* f! A* @6 l% U0 T8 l/ f
  8. elif n == 1:
    4 k7 c7 _$ j! B9 c! T
  9. if st.get('chat1') == None :
    6 O, R1 J% H  f7 N
  10. st.set("chat1", "true")
    ! |) K2 `+ |, O& ~. r, s
  11. return "Chat1.htm"& W7 O( _6 ^( ~+ {
  12. elif n >= 4:
    5 n; f1 F4 S. b7 T/ W& @
  13. return "Chat4.htm"
    : g) m2 M' M; }3 T4 x9 i
  14. return "Collected "+str(n)+" of 4 fangs": {% J" `6 ^9 V9 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.( T- h" f' D- Z7 P( ~

8 a) D8 P" G- z6 W4 d

, i; m8 R. f$ x9 S" |. Z7 [Вот конечный рабочий вариант квеста:! z/ S# X. H; k! F+ t7 W. m" _# r
  1. import sys$ r# b7 E3 v" q% M- g
  2. from net.sf.l2j.gameserver.model.quest import State
    ( E- W6 J0 q! [+ c- _$ P+ ?
  3. from net.sf.l2j.gameserver.model.quest import QuestState
    9 K9 ^/ N- @6 S+ {* G' k9 O( z6 i
  4. from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest, [  ?6 Z3 {3 T# {
  5. * f: B9 d; L; j5 t
  6. KELTIR_NPC_ID = 12082
    / ?- Y2 I0 ~1 x) L, w* Z- L; ]
  7. FANGS_ITEM_ID = 18595 {* ^% g6 ~8 v# \" {, T8 i
  8. DROP_RATE    = 500000( |5 w6 z! f8 o3 Y% m. f9 E1 L0 c+ b2 a

  9.   D+ e; n* N8 P+ Y
  10. WORLD_MAP_ITEM_ID = 16652 R) [5 m5 H% L1 r7 M2 g8 s

  11. ! Y7 B: O: G: C$ B$ ~$ \! K1 Z
  12. def getCount(st) :
    : |; B8 ?8 C3 {$ e6 m6 B8 j
  13. return st.getQuestItemsCount(FANGS_ITEM_ID)
    ( {+ N. X9 U$ C  i* v) p

  14. 0 h: m/ K" b0 Y# I3 q) K, q5 e, j
  15. def completed(st) :
    5 x: Y) `1 D2 \8 n4 Q% C+ v
  16. st.setState(COMPLETED), i  d2 m7 l5 g$ k* n/ ^
  17. st.clearQuestDrops()
    6 M0 @6 d1 Q- q  h# c) E
  18. st.takeItems(FANGS_ITEM_ID,-1)( g( r. W% u" G
  19. st.giveItems(WORLD_MAP_ITEM_ID,1)
    # S0 g, @7 ^1 y* \$ s* K3 _- w& ]
  20. st.exitQuest(False)
    * k  l. k' z9 D0 h; Y) h
  21. return
    , h. V. B5 B" d
  22. 4 G( L1 _. A$ E5 P
  23. def check(st) :8 M: z7 A: B; W! w2 E: U7 [
  24. if getCount(st) >= 4 :
    # l  C) P7 M/ S& y, j/ |
  25. completed(st)8 d# |' x) E$ l4 f+ o- J
  26. return+ W. v# d: D# ^
  27. # m5 h8 V" H- S8 _. @% R
  28. class Quest (JQuest):% Q; z+ T* p7 ^9 K

  29. 6 h% W* a1 z1 k6 L  F7 f
  30. def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)! d9 ^: Z$ m, B  G9 V' L( q# d
  31. " H% f- S- a. I! o* e  s
  32. def onEvent (self,event,st):
    7 N$ f/ k0 f; e9 D9 t$ `
  33. id = st.getState()
    . |9 ?1 \$ V2 F; f4 t; @
  34. if id == CREATED : st.setState(STARTED)
      C7 j9 K6 Z, z. y
  35. elif id == COMPLETED: pass
    + E8 c' e# x* Z. O( x% H8 w
  36. elif id == STARTED : check(st)4 {8 H1 M' W; J$ m, r- n* B
  37. return; p+ S" i% {5 v' Z! S

  38. 7 c4 q8 B6 u/ z% _
  39. def onKill (self,npcId,st):
    1 t) P( I. j8 o3 e% V5 ~
  40. if npcId == KELTIR_NPC_ID:3 Q! N1 A9 m! s2 k: O& ?2 }4 j
  41. n = getCount(st)  F, R/ S3 J! ]8 E
  42. if n == 0:+ |- F6 k7 m& j( B
  43. if st.get('chat0') == None :
    7 E5 i1 ?; F" o3 b
  44. st.set("chat0", "true")
    * E; ~( b. U6 Y" k
  45. return "Chat0.htm"+ h; K' R+ L6 e, J$ F
  46. elif n == 1:
    1 J$ l7 ]) a* C# z
  47. if st.get('chat1') == None :+ Q$ w( w9 v0 o* {
  48. st.set("chat1", "true")
    ) N+ x% Y$ y- o# @* r, h. T* V
  49. return "Chat1.htm"
    4 I' Q3 N; P" q6 [& w
  50. elif n >= 4:
    - Z0 P9 V$ d/ E  m. {  }
  51. return "Chat4.htm"2 K+ B1 p+ R; a+ x/ Y+ G
  52. return "Collect "+str(n)+" of 4 fangs"
    . H  ~4 L5 a9 t' E3 t/ y! x
  53. return
    ! [/ g: |' ^" H7 _( L1 O, N

  54. / C) Y; u' r; t+ Y& u
  55. QUEST    = Quest(201, "Tutorial", "Tutorial quest")
    # r$ w% E) J4 n3 j% o# R1 b+ n
  56. CREATED = State('Start',    QUEST)
    / z- `9 s8 e6 Q- I8 g; ^
  57. STARTED = State('Started', QUEST)3 ?' f, l$ Y  y4 R' U, C, Y/ p
  58. COMPLETED = State('Completed', QUEST)" ]+ ~' t( M3 Q/ R+ H% b# q

  59. 2 d& c0 ]6 t" _" `; U3 r7 G
  60. QUEST.setInitialState(CREATED): {$ @" B) ~* ^3 A
  61. QUEST.addStartNpc(7056)
    : V; A' z' k) n, o# r
  62. QUEST.addStartNpc(7012)
    # D6 W- o$ c& @
  63. QUEST.addStartNpc(7009)
    : V; E) c- w8 M8 A1 k/ N/ H
  64. QUEST.addStartNpc(7011)9 [1 @! a* B1 \

  65. ' J2 o% g: Z7 \$ _7 D2 @
  66. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
    ! }- i6 F# Y8 f4 D/ j0 c
  67. STARTED.addKillId(KELTIR_NPC_ID)
    % @, }( x- h( R! ?6 |
  68. STARTED.addTalkId(7056)- d4 Y$ x- p& z1 z5 g. w6 S6 I
  69. STARTED.addTalkI d(7012)
    / I2 y3 n- Q* o4 P' [/ ~$ ?/ G
  70. STARTED.addTalkId(7009)) b9 j* ]+ b6 @+ b5 w# v. B9 L1 h9 q
  71. STARTED.addTalkId(7011)
Скопировать код
9 R  R: X4 y! M  n

/ X, D3 T  X$ r. ~
Чтобы ответить, вам надо авторизироваться в системе Вход | Зарегистрироваться

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

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

638638758

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

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

admin@artace.ru Онлайн

QR-код

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