Top.Mail.Ru

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

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

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

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

x
Хроники        Interlude
8 [( E; {3 Y) p3 [Сборка        L2j
! M8 c  _1 v6 g. h1 M4 ?2 bОбратите внимание: в файле htm стартового NCP обязательно должна быть ссылка на квест:
9 n! l* x; ]* C+ f# N
  1. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста:( j" K1 ]) H; h
/ {% {, {: Q5 o/ }9 v
  1. if getCount(st) >= 4 :
    1 n& w6 h" ~- g
  2. completed(st), i$ \' e; R) |6 I, R% ^4 U! {7 |
  3.   return
    : O, @( q& P- F4 b/ ]! f
  4. : T0 ^) C' H. {+ _+ V& h$ T+ ]; r
  5. class Quest (JQuest):
    ) L* M7 q7 S& _& N/ G8 {' f
  6.   def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)
    - `; z& t2 o4 B, G
  7.   def onEvent (self,event,st):
      R' d( r! }7 _3 J
  8. id = st.getState()
    1 T% F' z- [) H! P  b
  9. if   id == CREATED  : st.setState(STARTED)# p1 V- O3 Z# N3 C
  10. elif id == COMPLETED: pass
    . Z5 ]3 n. u8 P
  11. elif id == STARTED  : check(st)% \/ H# w7 G7 |. M2 h
  12. return
    ) e* o+ \* f. F0 Z" z3 f0 P( R

  13. ; r& A! ^$ k2 S, m& \; m, D
  14. QUEST     = Quest(201,"Tutorial", "Tutorial quest")  T& B# _- o/ h& Q2 N7 `6 P
  15. CREATED   = State('Start',     QUEST)+ I8 X  G* k6 W* S8 t% r3 R
  16. STARTED   = State('Started',   QUEST)
    ; J- h* R/ V) ^
  17. COMPLETED = State('Completed', QUEST)
    - N. y  q) w4 h
  18. 5 ~, \& w" D5 X+ Z$ z- e: }; }
  19. QUEST.setInitialState(CREATED)
    9 f% O7 b  U. \
  20. QUEST.addStartNpc(7056). @2 ^' h2 x: N9 o4 j" B
  21. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Теперь рассмотрим, как это работает.
1 ~0 c, g9 |- EИгрок подходит к начальному NCP (в данном случае 7056), нажимает на «Quest». Квест будет создан и состояние квеста перейдет к CREATED и игроку будет показана страничка Start.htm с описанием квеста. Тогда метод onEvent, поле открытия странички Start.htm переведет состояние квеста в STARTED и игроку будет показана страничка Started.htm, где будет опсание того, как найти keltirs и .т.д.; o6 N1 ]9 _7 x# |( W* W* D7 h7 o; k
5 n- Q! _+ P3 \: S/ D3 h

: u7 ^5 o. d+ z# a" G) {" lПри состоянии STARTED будет зарегистрирован дроп «fangs» при убийстве keltirs. Игрок может вернуться к стартовому NCP и спросить о квесте – метод onEvent будет вызван снова. Если у игрока не хватает необходимого количества предметов, то метод check() не переведет квест в следующее состояние и Started.htm будет показана снова. Но если игрок собрал необходимее количество предметов (в данном случае 4 клыка), то метод check() вызовет метод completed() который переведет квест в новое состояние COMPLETED, заберет все клыки, даст карту мира, т.к. это награда за квест, покажет Completed.htm и завершит квест.% Q# Q" P& o4 F. h- {6 ]

" o( P* l3 ^1 u2 ^) j7 g8 [
' ^0 E& d7 |' n
Теперь давайте сделаем наш квест более похожим на то, что он должен из себя представлять.! u! ?1 L0 d; w" K9 s* p
Прежде всего у нас есть 3 метода для объявления их в Яве – onTalk, onKill и onEvent. Если методы onTalk и onKill не объявлены, то за них все будет делать метод onEvent, т.е. определять квестовых монстров и вызывать диалоги NCP. Есть примечание, методы onTalk и onKill будут вызывать только диалоги с NCP в зависимости от текущего состояния квеста. Метод onKill будет вызываться только тогда, когда мы убиваем квестового монстра.6 k" R8 y4 G, B  q
* j# w! q: O0 Y% y8 M' J
( \% W2 X* v: \7 ^7 _
Давайте рассмотрим как вызывается метод onKill при убийстве keltir в состоянии квеста STARTED:+ \: @7 V2 p# S' v9 Y) J# @+ U
  1. STARTED.addKillId(KELTIR_NPC_ID)
Скопировать код
и метод onKill в классе Quest:
2 O& T& W- T. B2 o
5 D; z: l. t2 o  G* y* O8 P
  1. class Quest (JQuest):0 R8 X0 z# t9 y! S
  2.   ...3 {3 O" d1 V1 C8 m8 ]2 \4 V
  3.   def onKill (self,npcId,st):
    / F2 x8 [& O( `0 S0 o% J9 _$ X
  4. if npcId == KELTIR_NPC_ID:- y. F4 k7 d9 s6 B
  5.    n = getCount(st)
    ( K! \1 \1 `8 g* |, M" S& G5 ^
  6.    if   n == 0:  z3 m3 z/ W& v2 N2 R
  7.        return "Chat0.htm"
    8 T6 U1 ~! ]6 d5 D
  8.    elif n == 1:  L7 k7 D. {( O! n9 _
  9.        return "Chat1.htm"( M" R$ X% w$ o* M# i
  10.    elif n >= 4:5 c' H, R2 s& @# u
  11.        return "Chat4.htm"6 O0 d5 h2 t. R5 i- g8 n- t
  12.    return "Collected "+str(n)+" of 4 fangs"
    & x4 k- X! N* l) @
  13. return
Скопировать код
Метод onKill (а так же метод onTalk) имеет следующие параметры:
7 O4 L% L. U3 y6 S, Y8 e5 \- C% S/ W# ?4 t$ @! Y* G

; U- n* K. k" p/ o0 X) z• self – квест% _. S8 m3 N, U: `
• npcId – ID NCP, которого мы должны убивать (если это метод onTalk, то ID того NCP, с которым мы должны поговорить).6 _) W$ @9 i7 [" g$ ^5 }
• st – текущее состояние игрока.. m0 g" `# X, q7 K, W- l6 R' h8 Y6 h: [
$ v( \4 `/ ~( Z0 x8 _  c$ a/ \1 n! D% [
: {$ W$ b4 C0 Z5 O3 Y- r
В этом методе мы проверяем и отмечаем, является ли убитый NCP keltir’ом. В основном эта проверка не нужна, т.к. у нас только KELTIR_NPC_ID.
. ?/ [  [$ {# ]3 C3 n0 w4 [# K' w- w( X, N# x% L! F
  V. w: l# y7 ?( @
Затем проверяем количество предметов (в данном случае количество клыков), и если их вообще нет, то возвращаем строку "Chat0.htm", если только один предмет, то возвращаем строку "Chat1.htm", если же предметов 4 или больше, то "Chat4.htm". Если строка возвращена из методов onEvent, onKill или onTalk, то сервер покажет соответствующие htm. В Chat0.htm может иметь следующий текст: «Вы не имеете ни одного клыка, возвращайтесь позже, когда соберете 4 штуки и бла, бла, бла…», в Chat1.htm может быть следующий текст: «У Вас всего 1 клык, по этому соберите еще…». В Chat4.htm – «Вы собрали необходимое количество предметов, возвращайтесь к вашему тренеру, что бы завершить квест…»3 _/ c# E1 w0 W8 J( r7 F
& L1 W) D' s$ p7 r* v5 K2 j. B

: b2 k: Y7 H& jПримечание: если в строка return начинается с "<html>", то будет показана страничка html с текстом, который стоит далее. Так вместо:
4 |/ I; B9 ?4 q/ b0 yreturn "Chat4.htm"/ C9 m7 K8 b" S! }8 r9 V0 Z* h

. U+ x' s6 p/ v. f  O$ F

- Y6 k# H  O* R; H4 ]можно поставить:  v/ @* U: z0 e2 Q  b3 N' v
  1. return "<html><body>Return to your trainer to complete the quest</body></html>"
Скопировать код
Так же если строка заканчивается без .htm или в начале нет <html>, то текст будет выведен, как системное сообщение в окне чата. В нашем случае мы сделаем так, что бы при каждом убийстве keltik выводилось системное сообщение: «Собрано N из 4-х клыков».( B- a- U3 F& j* I8 _

7 I# M; ^; k2 x% ?+ Z/ b( Z
+ N8 Q8 S# u6 Q2 Q
Наш код для onKill имеет один недостаток. Он будет постоянно показывать Chat0.htm, Chat1.htm и Chat4.htm, нам же необходимо, что бы Chat0.htm и Chat1.htm показывались только один раз. Как нам это сделать? С помощью переменных.
3 d: ?  y" V: Q
. N* J. ~' i" O. |7 G; s

; k2 Z: H! J9 o9 G1 \В каждом квесте строки могут храниться с помощью переменных. Эти переменные сохраняются в Вашей БД. В каждом методе мы можем назначить, прочитать и удалить переменные. Давайте изменим метод onKill, так что бы каждый диалог вызывался только один раз.: w; k+ v# n8 r! M/ F+ \# c! }
  1. def onKill (self,npcId,st):  h* a6 S, D$ {' I4 E
  2. if npcId == KELTIR_NPC_ID:
    $ }  T! U6 F- u2 d
  3. n = getCount(st)
    % ?2 }" j% m% D9 L$ _2 P3 R
  4. if n == 0:4 E* D7 _& G& U9 Y: q# ~
  5. if st.get('chat0') == None :
    6 G: i5 v& w7 Y2 V- E1 P1 Z8 u
  6. st.set("chat0", "true"), D$ q8 M6 |/ ~0 L+ b9 j
  7. return "Chat0.htm"
    7 U9 Y5 N4 s, N' ~+ N' b; c
  8. elif n == 1:3 M" ]  G. [9 b  E6 x+ E
  9. if st.get('chat1') == None :
    : `. H$ M& W8 h# t5 ~" M
  10. st.set("chat1", "true")
    ; @' e( Y) U8 N8 `( _
  11. return "Chat1.htm"
    % }0 |6 y/ K9 e% b8 z
  12. elif n >= 4:2 }4 ~+ F  {2 q4 K
  13. return "Chat4.htm"
    2 i. M* r8 {1 |( {: y
  14. return "Collected "+str(n)+" of 4 fangs"9 g, I% P; t* \9 ]: `0 v2 }4 X$ 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.
4 n1 X1 }$ `5 i4 V- G: N% ]/ c3 K: m. G$ z$ w( ^! ?

  X* b2 i' {# b* Z( e  k4 C# kВот конечный рабочий вариант квеста:
( `4 _( L, h1 r# t
  1. import sys! G! }5 y* ?/ P. \
  2. from net.sf.l2j.gameserver.model.quest import State
    " ~# ?+ |5 C* O9 J
  3. from net.sf.l2j.gameserver.model.quest import QuestState
    9 C9 U3 O. T% A% f, I: h6 {& Z
  4. from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest4 s& ?& F3 o7 g

  5. ' ]$ u( r( M  ^3 O# V+ `& C
  6. KELTIR_NPC_ID = 12082
    9 E- \& \/ Z" g/ X' k
  7. FANGS_ITEM_ID = 1859
    ! K- ?5 L8 u- D: X
  8. DROP_RATE    = 500000
    7 @9 y9 W6 Z4 R4 D" n4 V$ H

  9. 7 [4 q/ J! s: `$ o1 X' e6 W, }' k* \1 D
  10. WORLD_MAP_ITEM_ID = 1665, ?* ^& ]: ^% q2 e% v, c' Q$ {
  11. 1 V8 I  U- A- ?- k. [5 h
  12. def getCount(st) :! Z) k$ k5 q) F, f& @4 q% x
  13. return st.getQuestItemsCount(FANGS_ITEM_ID); Q0 E2 e3 t( {& u) T+ C
  14. ) ^. l' X" a$ N, s5 Y. r" q8 H
  15. def completed(st) :" F4 Z% [! N( `. H) B
  16. st.setState(COMPLETED)
    1 {4 H2 v, r& O9 X& G* u( c) e. z. m, c
  17. st.clearQuestDrops()& r' v+ m# A4 x2 ?& B
  18. st.takeItems(FANGS_ITEM_ID,-1)$ f5 G! j5 J2 U% g& P
  19. st.giveItems(WORLD_MAP_ITEM_ID,1)" y% z. ]5 b8 f7 P/ T& S8 h2 b3 F1 _
  20. st.exitQuest(False)
    : m, G/ f0 {$ V" h% g& o+ ]
  21. return/ ]2 m  l! U) H

  22. - h& G2 B( p( w# H" q8 O" U0 R
  23. def check(st) :$ x3 ]' g; @! S4 |: ^! H  ~
  24. if getCount(st) >= 4 :
    - E: y9 f! L  h8 A- a
  25. completed(st)
    * F' F) G7 Z4 K
  26. return
    0 f* y1 T4 {; L/ X8 `) d9 M
  27. ! ~4 @$ J: A' x
  28. class Quest (JQuest):
    : b; ~, Y8 n! ~
  29. " I- f! z6 i- \8 v
  30. def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)6 s; g+ T" Z% Y8 w( X# ]# {+ G
  31. - h1 l9 Y2 ^/ J
  32. def onEvent (self,event,st):
    5 F  j2 v2 l  I' g' d3 {
  33. id = st.getState()
    % Z! y8 R) S$ |7 V3 Z& _
  34. if id == CREATED : st.setState(STARTED)
    # _8 [1 |' m" O2 K: g
  35. elif id == COMPLETED: pass
      ]! g# J# P5 w# @
  36. elif id == STARTED : check(st)* s, J' D& w& F3 R$ T
  37. return
    % g, U: H' o; S9 ?+ y* w

  38. + z+ `. k' R( U( S' t( J* h9 \: F; O
  39. def onKill (self,npcId,st):
    0 O! e) I+ I" c' N0 G1 ~- U; F
  40. if npcId == KELTIR_NPC_ID:
    ; s; G. `7 K4 |
  41. n = getCount(st)
    9 Z/ e7 }, ~$ X  `; X# g  g
  42. if n == 0:* M/ j' \5 O  L1 i/ i6 B2 p6 H* O
  43. if st.get('chat0') == None :0 z3 [# f7 q4 }* M& N+ \
  44. st.set("chat0", "true")# I5 p$ |: W1 d, L( p
  45. return "Chat0.htm"0 H4 D1 r# H- U$ J0 A3 f/ [
  46. elif n == 1:/ B  @5 j9 {, O$ H9 \
  47. if st.get('chat1') == None :
    ) \7 u2 h  r' L2 @2 j, X( {- D
  48. st.set("chat1", "true")& l$ n! n! U9 n2 j
  49. return "Chat1.htm"2 e7 W5 b: v/ r7 I
  50. elif n >= 4:1 ?! r1 @' e& o
  51. return "Chat4.htm"
    - [+ ~. O, B' G) [2 F+ @. P
  52. return "Collect "+str(n)+" of 4 fangs"# X: ?  C/ w) V
  53. return
    " A+ w% L! o, w$ V& r1 H
  54. ) e+ D0 x+ K% r+ G% S1 h. }4 F: k# f
  55. QUEST    = Quest(201, "Tutorial", "Tutorial quest")8 F3 s" C8 {- e; V
  56. CREATED = State('Start',    QUEST): n# K3 _; }4 y$ h$ n1 _- I
  57. STARTED = State('Started', QUEST)" T$ I  E) P# z/ M3 T
  58. COMPLETED = State('Completed', QUEST)
    1 b8 ~* K5 V: w7 D, T  P

  59. 5 J( g+ V: ?, D
  60. QUEST.setInitialState(CREATED)
    $ H. _! v, q; t9 b" ^. \# |4 W* i+ @- l
  61. QUEST.addStartNpc(7056)  |( _7 N9 e/ ]' ^* f; F7 J
  62. QUEST.addStartNpc(7012)3 z# h' S; b4 R0 {9 I5 U1 N8 W
  63. QUEST.addStartNpc(7009)8 K& O$ k7 S; i( B. N
  64. QUEST.addStartNpc(7011)
    + j  ~2 E, q# G6 {
  65. ) W! B# D4 @( d( |* c2 I5 z9 b( X/ @4 `
  66. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)9 I' F" {4 A5 w0 l! J$ o
  67. STARTED.addKillId(KELTIR_NPC_ID)
    3 m! F/ F: q) `4 j2 \2 }
  68. STARTED.addTalkId(7056)+ o- g+ O8 D8 S" Z
  69. STARTED.addTalkI d(7012)
    $ k. t7 y& X5 b# F2 o: p
  70. STARTED.addTalkId(7009); W. K2 x1 M3 j/ Y. D1 @+ z( G
  71. STARTED.addTalkId(7011)
Скопировать код
3 w' C( i* T! x$ j. P: h7 G3 _7 y

7 E. ]2 ^: t. a2 {2 ^0 _
Чтобы ответить, вам надо авторизироваться в системе Вход | Зарегистрироваться

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

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

638638758

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

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

admin@artace.ru Онлайн

QR-код

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