Top.Mail.Ru

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

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

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

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

x
Хроники        Interlude' A! S/ V" m# A" X
Сборка        L2j
' F* `: C, W" nОбратите внимание: в файле htm стартового NCP обязательно должна быть ссылка на квест:
! |. @7 j" C" h. U
  1. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста:
% c( ^. G4 [" z6 J5 p' ^6 h6 O0 }2 l. H0 y/ {( ^
  1. if getCount(st) >= 4 :# Z; l- j* z9 q
  2. completed(st)6 o- Q" e& r& e( I
  3.   return" i% n( \/ F$ l* G" E" |4 A9 ]! I
  4. & J  [, S5 t1 o3 Y/ T* m3 _* G
  5. class Quest (JQuest):
    0 h2 \1 |# ]4 ^7 |# h; w, o
  6.   def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)5 p( o7 D. q' O4 K( l
  7.   def onEvent (self,event,st):
    6 W5 w+ V& Q' c0 `
  8. id = st.getState()) p) r4 P' I9 @) E
  9. if   id == CREATED  : st.setState(STARTED)
    ( ^& \. `6 h/ x/ s: \. ], u( Z
  10. elif id == COMPLETED: pass& K$ E, {/ \, B+ a6 x
  11. elif id == STARTED  : check(st); W) B$ G3 K8 F
  12. return
    2 y( c7 B6 l8 a7 L
  13. ! m: b" g7 u. F6 y0 _
  14. QUEST     = Quest(201,"Tutorial", "Tutorial quest")& ?% ~% A& P+ I& r( d- V6 b
  15. CREATED   = State('Start',     QUEST)+ D6 ^) _* N- O, Q' t5 a1 d2 ]. H
  16. STARTED   = State('Started',   QUEST)
    5 l4 O0 a& r9 Z) w1 P3 O
  17. COMPLETED = State('Completed', QUEST)
    0 L  m+ `5 w: v) h; E3 V8 T

  18. / `- t9 f1 j3 X. {0 U+ @
  19. QUEST.setInitialState(CREATED)
    9 u9 t; T' Q" s2 s3 v' u+ t
  20. QUEST.addStartNpc(7056). H' s( f' f6 ]. C% |
  21. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Теперь рассмотрим, как это работает.* n/ i/ c6 @4 c( _
Игрок подходит к начальному NCP (в данном случае 7056), нажимает на «Quest». Квест будет создан и состояние квеста перейдет к CREATED и игроку будет показана страничка Start.htm с описанием квеста. Тогда метод onEvent, поле открытия странички Start.htm переведет состояние квеста в STARTED и игроку будет показана страничка Started.htm, где будет опсание того, как найти keltirs и .т.д.
! H1 s" I6 }- T. c# f" m* P* R. A0 I$ f" t( ?$ \

/ z. u( Q, ~' G* WПри состоянии STARTED будет зарегистрирован дроп «fangs» при убийстве keltirs. Игрок может вернуться к стартовому NCP и спросить о квесте – метод onEvent будет вызван снова. Если у игрока не хватает необходимого количества предметов, то метод check() не переведет квест в следующее состояние и Started.htm будет показана снова. Но если игрок собрал необходимее количество предметов (в данном случае 4 клыка), то метод check() вызовет метод completed() который переведет квест в новое состояние COMPLETED, заберет все клыки, даст карту мира, т.к. это награда за квест, покажет Completed.htm и завершит квест.
; M1 r* D1 |9 q# A' `$ ^' n$ e5 Q4 _; G0 @6 ]  o

( x/ u9 H2 K/ m6 F; L$ {Теперь давайте сделаем наш квест более похожим на то, что он должен из себя представлять.
, ~  x. m4 U9 U# K& t. L) FПрежде всего у нас есть 3 метода для объявления их в Яве – onTalk, onKill и onEvent. Если методы onTalk и onKill не объявлены, то за них все будет делать метод onEvent, т.е. определять квестовых монстров и вызывать диалоги NCP. Есть примечание, методы onTalk и onKill будут вызывать только диалоги с NCP в зависимости от текущего состояния квеста. Метод onKill будет вызываться только тогда, когда мы убиваем квестового монстра.
( W# r( Y, \0 S5 I& ?: M
$ w: X+ n  J9 k3 u; Z0 [
3 X7 b/ E, P1 ]( H/ f# t
Давайте рассмотрим как вызывается метод onKill при убийстве keltir в состоянии квеста STARTED:
1 `1 Y5 o) b" P
  1. STARTED.addKillId(KELTIR_NPC_ID)
Скопировать код
и метод onKill в классе Quest:
; ~/ X: V3 H8 n7 j' A% @' x5 Z8 t) Q7 ?, s: R- ^$ E) ?8 [' D3 \
  1. class Quest (JQuest):
    ' @0 ]! e4 `1 z! C+ D
  2.   ...
    / ~0 E$ ]7 f8 T" I: I9 U6 V
  3.   def onKill (self,npcId,st):
    5 V( K# r0 a& ~1 A2 d
  4. if npcId == KELTIR_NPC_ID:1 e+ I  K( G8 \* ^
  5.    n = getCount(st)
    0 g; A9 |5 `" L# Y( c
  6.    if   n == 0:
    9 a2 J0 @8 z$ M( ~5 g8 a+ @: q4 m* H
  7.        return "Chat0.htm"
    / g7 A' S1 i( n. }
  8.    elif n == 1:
    ; \# `3 ~) f% W4 f
  9.        return "Chat1.htm"
    ) n9 W  B8 X) B
  10.    elif n >= 4:
    " [* ]6 E4 i' j1 w0 h( u- W
  11.        return "Chat4.htm"
    . N: _- `6 v/ H4 E5 d
  12.    return "Collected "+str(n)+" of 4 fangs"5 i& M; B7 Y! x  T5 |$ `2 F$ z
  13. return
Скопировать код
Метод onKill (а так же метод onTalk) имеет следующие параметры:$ j) S) c: y. g8 j, ~7 J
* t8 d+ M, C% c

' p8 y  e/ [* J9 i( o* o7 O: ?• self – квест8 i2 ~& J* H) b
• npcId – ID NCP, которого мы должны убивать (если это метод onTalk, то ID того NCP, с которым мы должны поговорить).
7 U; A: R, a" L3 {  }• st – текущее состояние игрока.! d+ @& V$ ?! c# b$ u/ v
' p7 e; i0 Y+ N. @' ^

, U6 m& y7 @; {В этом методе мы проверяем и отмечаем, является ли убитый NCP keltir’ом. В основном эта проверка не нужна, т.к. у нас только KELTIR_NPC_ID.
) G6 R0 _3 u  n+ [; i
. M+ g; q0 h  Q, s8 v* w
* X6 x4 m4 ?* U$ N* i3 Y
Затем проверяем количество предметов (в данном случае количество клыков), и если их вообще нет, то возвращаем строку "Chat0.htm", если только один предмет, то возвращаем строку "Chat1.htm", если же предметов 4 или больше, то "Chat4.htm". Если строка возвращена из методов onEvent, onKill или onTalk, то сервер покажет соответствующие htm. В Chat0.htm может иметь следующий текст: «Вы не имеете ни одного клыка, возвращайтесь позже, когда соберете 4 штуки и бла, бла, бла…», в Chat1.htm может быть следующий текст: «У Вас всего 1 клык, по этому соберите еще…». В Chat4.htm – «Вы собрали необходимое количество предметов, возвращайтесь к вашему тренеру, что бы завершить квест…»+ o) u/ G+ c8 j7 }
7 }  i7 W3 Q2 q% o1 i! d

5 _0 ^7 A# h: s' y. a: A& \Примечание: если в строка return начинается с "<html>", то будет показана страничка html с текстом, который стоит далее. Так вместо:
1 ]8 h# O6 A- M3 d6 f2 kreturn "Chat4.htm"
) I8 y3 t2 r6 W7 ~; h& g5 `# ^
1 S8 W% ~+ M7 b! m5 |1 @+ T4 I

% W, r. V- ~* W1 F! D6 \! W2 iможно поставить:6 n# ~* J6 i5 n& [
  1. return "<html><body>Return to your trainer to complete the quest</body></html>"
Скопировать код
Так же если строка заканчивается без .htm или в начале нет <html>, то текст будет выведен, как системное сообщение в окне чата. В нашем случае мы сделаем так, что бы при каждом убийстве keltik выводилось системное сообщение: «Собрано N из 4-х клыков»./ j2 `+ E7 P) i2 t% X) C$ x
, ?: y" E* a+ R: j. U9 {# p

4 j% m' N4 f: f* }8 \7 T- p! GНаш код для onKill имеет один недостаток. Он будет постоянно показывать Chat0.htm, Chat1.htm и Chat4.htm, нам же необходимо, что бы Chat0.htm и Chat1.htm показывались только один раз. Как нам это сделать? С помощью переменных.
( ?0 e+ m( L' i6 I% i# y. ]$ I/ T, s0 x) F

. r4 A* v" }- K" c2 u9 Z. ZВ каждом квесте строки могут храниться с помощью переменных. Эти переменные сохраняются в Вашей БД. В каждом методе мы можем назначить, прочитать и удалить переменные. Давайте изменим метод onKill, так что бы каждый диалог вызывался только один раз.$ @0 V  @3 k; T
  1. def onKill (self,npcId,st):
    & P9 Y, ^! G4 l- m
  2. if npcId == KELTIR_NPC_ID:* P4 l+ J" l6 f6 m, p9 ?8 e8 {
  3. n = getCount(st)6 W7 A% D5 D5 h
  4. if n == 0:
    - b8 f- v7 I6 J+ Y, C0 ?
  5. if st.get('chat0') == None :
    & S( n( {6 \0 Z1 @
  6. st.set("chat0", "true")$ F2 U, m- i, u+ R. ^3 E8 ?
  7. return "Chat0.htm"
    ) _1 E* t& _; I3 \
  8. elif n == 1:* V# O, Q5 V" N' D4 S; n
  9. if st.get('chat1') == None :
    ( m! Y6 _8 B% u9 T" ~
  10. st.set("chat1", "true")
    + h# X1 ~# o- h9 C; `
  11. return "Chat1.htm"
    2 k" {( |6 ^0 V& U
  12. elif n >= 4:6 Z! R0 ?6 t: R$ X, n7 b& n+ ?% q+ X
  13. return "Chat4.htm"4 C6 |- u7 b; Y2 Y
  14. return "Collected "+str(n)+" of 4 fangs"$ X6 \% l8 ~/ u, v
  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.
; X' M) _% A) }0 V4 _
3 k6 h- G( i1 @8 y! y# Z( K$ z5 ^
+ N% y. g* ^% k& ?  y4 c$ t3 f8 n, `
Вот конечный рабочий вариант квеста:
# ]  i2 a" R' g( v8 Y$ A2 G
  1. import sys
    $ @. K3 W* i7 t$ T7 ~
  2. from net.sf.l2j.gameserver.model.quest import State
    9 x' e" d' y# \* Y6 g. I
  3. from net.sf.l2j.gameserver.model.quest import QuestState4 [. F) h) o4 x
  4. from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest; g* h% L; d# S$ [2 I" n
  5. 7 K3 s, J- H' U" a6 C2 F
  6. KELTIR_NPC_ID = 12082$ b6 _4 f6 K1 d) N: _! s
  7. FANGS_ITEM_ID = 1859: G; s3 f# X* Q$ Z8 V+ v0 H
  8. DROP_RATE    = 500000
    : E8 P) q% }4 n+ _5 x2 c8 o$ h

  9.   D- K5 W% l8 l% M6 G* @# C8 ~
  10. WORLD_MAP_ITEM_ID = 1665
    8 `+ e, }, I, ]

  11. 2 L! r* X8 ?; X' B' x5 M" X
  12. def getCount(st) :& K2 j. p$ m% _  S9 {
  13. return st.getQuestItemsCount(FANGS_ITEM_ID). u: G8 `% Q( }
  14. 9 x; a3 [# y0 I: F
  15. def completed(st) :
    % m  v1 x; P; R5 I! D
  16. st.setState(COMPLETED)
    ( T* {* m5 e) N
  17. st.clearQuestDrops()* L0 O3 c: Y, u: J+ n% o' v
  18. st.takeItems(FANGS_ITEM_ID,-1)1 C+ |  e, x' f% `! _9 F
  19. st.giveItems(WORLD_MAP_ITEM_ID,1)
    . u9 A: K' p3 y! ?0 b7 u# _
  20. st.exitQuest(False)
      Q+ b+ t* F1 e$ Q
  21. return% i) q! y5 ^) S* x6 u- u

  22. . |% O, J* S- G1 N8 g6 @; _
  23. def check(st) :
    * |6 k. C+ o; M: R/ v1 ]
  24. if getCount(st) >= 4 :
      h! Y, g' ]5 F: Q/ a
  25. completed(st), o8 y( K! M% y1 ~+ @3 A
  26. return) \& h: y8 m- C; F% g) v

  27. & {# z) |$ [4 E/ p
  28. class Quest (JQuest):7 {+ ]2 R, d6 J1 H$ {4 M

  29. 9 F& _) R, f2 g$ H) q+ Z# w
  30. def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)
    , t& E3 f% t, N, f) f7 d4 C$ g
  31. 7 v$ ~. g; u" F% o4 u7 D1 Y; M% y
  32. def onEvent (self,event,st):7 W3 p; h2 g" b( T, @- g; G
  33. id = st.getState()
    ) v, V/ r, `* O  B
  34. if id == CREATED : st.setState(STARTED)
    + S6 a" W6 w6 _' ~8 B  Y
  35. elif id == COMPLETED: pass; D5 I9 s: V: |3 B! ^1 f: ?
  36. elif id == STARTED : check(st)
    # \; @: h& ]  a5 ]& L) H
  37. return
    4 y2 o1 U# y: q; W- M
  38. ! e) {- t. I5 B5 Y7 i1 d
  39. def onKill (self,npcId,st):
    - u( Y7 q3 p1 K2 Q9 b* i5 I
  40. if npcId == KELTIR_NPC_ID:8 K- o% s6 [- G  S6 s* k
  41. n = getCount(st)
    ! A' F6 i) I* u3 v3 f4 c" H6 F  z' f
  42. if n == 0:
    & O9 a! h6 ~* X: z
  43. if st.get('chat0') == None :
    ) @3 \7 Y; z. P
  44. st.set("chat0", "true")1 J) ~4 R) p. c/ z
  45. return "Chat0.htm"
    ( Q  E% y. B1 I1 p; ?: C) `
  46. elif n == 1:
    , N' G. ^% v9 ~$ R
  47. if st.get('chat1') == None :1 n, [! q2 w' H" h& e9 G7 f8 z
  48. st.set("chat1", "true")2 P, G4 ]( F' k, I+ R
  49. return "Chat1.htm"
    8 ^7 X8 L- h& i: e& Q4 [0 O2 _
  50. elif n >= 4:2 y2 b7 k# G) ^3 ^# p* w
  51. return "Chat4.htm"' Y% P# F" O5 x! J  N: D
  52. return "Collect "+str(n)+" of 4 fangs"! d! S# U0 o" }& t: g& O
  53. return
    $ M7 n- X: ^, O' }8 H
  54. 2 u# v! O" b7 @) i. l- `
  55. QUEST    = Quest(201, "Tutorial", "Tutorial quest")- u3 b+ B7 n& a0 A) y9 Z2 Q8 P
  56. CREATED = State('Start',    QUEST)7 y  V. L# a7 A9 y
  57. STARTED = State('Started', QUEST)
    0 C8 Y9 }( \- x: _% g3 _
  58. COMPLETED = State('Completed', QUEST)6 Y( y& U" k4 g1 |* K! T8 D% |5 o( y

  59. 3 a+ Z7 l  E, |
  60. QUEST.setInitialState(CREATED)( D4 B, R, ]' n+ i2 |, G5 S
  61. QUEST.addStartNpc(7056)
    / h: Y" l& e7 v1 N
  62. QUEST.addStartNpc(7012)
    9 i7 d5 L0 Y  g* t6 |
  63. QUEST.addStartNpc(7009)
    6 L! Z0 z1 f. {( P, o
  64. QUEST.addStartNpc(7011)
    1 ~- K5 b& K/ ]9 X( J

  65. 0 }) F& ]. ?: m( m8 C
  66. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)1 W; x' p, c5 O+ W5 ~6 c
  67. STARTED.addKillId(KELTIR_NPC_ID): |3 i% [+ r" w, ?* _
  68. STARTED.addTalkId(7056): X4 }' y( t( x1 }2 u9 g% `" q
  69. STARTED.addTalkI d(7012)
    % ]+ S2 Z, |. N- h1 l9 ?' A
  70. STARTED.addTalkId(7009)2 b: P& w# w$ \8 u) h
  71. STARTED.addTalkId(7011)
Скопировать код
% r. K. X  G/ U

' w: v6 l( ?9 a4 K" ]
Чтобы ответить, вам надо авторизироваться в системе Вход | Зарегистрироваться

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

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

638638758

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

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

admin@artace.ru Онлайн

QR-код

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