Top.Mail.Ru

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

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

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

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

x
Хроники        Interlude, U, U3 @: H' g/ o
Сборка        L2j* j* a  I" u3 B9 f9 _, i* E/ ?
Обратите внимание: в файле htm стартового NCP обязательно должна быть ссылка на квест:2 |* o. t2 V- w
  1. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста:
$ V! n6 z( V$ j2 J% [, \& G& e" |' }
' s# j% T5 p7 R6 U' y6 p4 v  F- z! S
  1. if getCount(st) >= 4 :7 M3 X* {' R( b- S: D5 Z: {
  2. completed(st)
    6 o4 {3 ^2 q& F5 F2 ?' F, I+ @. C
  3.   return
    , W) l1 o( k& u9 f
  4. ( L" u" Q; K; w9 U) g8 G+ ?6 z# F
  5. class Quest (JQuest):
    0 {# \: V; U2 i% C6 Q- ?4 a9 @$ R
  6.   def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr). @, N  |2 S; `/ [0 |; |# W
  7.   def onEvent (self,event,st):/ M5 F, e* N" W: V+ M. P
  8. id = st.getState(). v* H, o4 L) L. d: x
  9. if   id == CREATED  : st.setState(STARTED)
    / V# _9 V+ ?6 J7 w6 T
  10. elif id == COMPLETED: pass
    * y* }5 b. ~" D) f5 j1 D
  11. elif id == STARTED  : check(st)+ q& Q6 P( i% B2 P# m
  12. return1 E9 v6 U% p: w6 d$ M

  13.   t" }8 I. n5 }* n* X" n6 B5 {
  14. QUEST     = Quest(201,"Tutorial", "Tutorial quest")
    ! E% l$ R5 R1 W2 c* V0 T  A
  15. CREATED   = State('Start',     QUEST)
    2 v) J& P# N' `
  16. STARTED   = State('Started',   QUEST)
    3 F- T0 u, o0 N
  17. COMPLETED = State('Completed', QUEST)9 k; }6 K' e' L: S' N9 w

  18. % p/ e4 h# n+ X; m
  19. QUEST.setInitialState(CREATED)6 w5 }9 P! w) }4 u
  20. QUEST.addStartNpc(7056)
    8 `: I  T/ a0 D6 G
  21. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Теперь рассмотрим, как это работает.
+ D  t) G- o! x$ Z- o  iИгрок подходит к начальному NCP (в данном случае 7056), нажимает на «Quest». Квест будет создан и состояние квеста перейдет к CREATED и игроку будет показана страничка Start.htm с описанием квеста. Тогда метод onEvent, поле открытия странички Start.htm переведет состояние квеста в STARTED и игроку будет показана страничка Started.htm, где будет опсание того, как найти keltirs и .т.д.4 @7 a) ~; D$ d. _
$ T9 w* p8 j( c
$ q0 R. k$ R, c) ]' f9 h
При состоянии STARTED будет зарегистрирован дроп «fangs» при убийстве keltirs. Игрок может вернуться к стартовому NCP и спросить о квесте – метод onEvent будет вызван снова. Если у игрока не хватает необходимого количества предметов, то метод check() не переведет квест в следующее состояние и Started.htm будет показана снова. Но если игрок собрал необходимее количество предметов (в данном случае 4 клыка), то метод check() вызовет метод completed() который переведет квест в новое состояние COMPLETED, заберет все клыки, даст карту мира, т.к. это награда за квест, покажет Completed.htm и завершит квест.
* J% I0 V" J9 F5 c/ y2 _; U! `
8 v, d: d) o- X

4 |: g4 c( \* y3 SТеперь давайте сделаем наш квест более похожим на то, что он должен из себя представлять.
! L' W9 f, H: @% E3 uПрежде всего у нас есть 3 метода для объявления их в Яве – onTalk, onKill и onEvent. Если методы onTalk и onKill не объявлены, то за них все будет делать метод onEvent, т.е. определять квестовых монстров и вызывать диалоги NCP. Есть примечание, методы onTalk и onKill будут вызывать только диалоги с NCP в зависимости от текущего состояния квеста. Метод onKill будет вызываться только тогда, когда мы убиваем квестового монстра.. K- }% `  p6 j0 p7 S* T
, X$ m9 D# F, m4 T- [% e- P
$ F# J4 x5 ~$ I; j( B2 i
Давайте рассмотрим как вызывается метод onKill при убийстве keltir в состоянии квеста STARTED:
* k% U" v0 d  r' T' M8 S2 p
  1. STARTED.addKillId(KELTIR_NPC_ID)
Скопировать код
и метод onKill в классе Quest:' [- X6 A7 y" i
5 B1 k. H$ M" a6 ~) d
  1. class Quest (JQuest):
    * {% j. h: c" i
  2.   ...% P8 b! r( [1 {1 Z& B  y& o
  3.   def onKill (self,npcId,st):" l, U; y- P7 z  M1 M0 S! j* ~
  4. if npcId == KELTIR_NPC_ID:
    . \; z3 G: ^; ~% e, K1 T
  5.    n = getCount(st)8 ]0 b5 b0 o( r$ t8 J+ R% Q- \8 ^
  6.    if   n == 0:' x, v, E2 S* e8 S8 z* S
  7.        return "Chat0.htm"
    + Z4 h& _# y4 h9 C6 V" Y# n
  8.    elif n == 1:
    6 x" R- F  I( j# s6 N
  9.        return "Chat1.htm") a1 l* S9 a3 @% Y& ]* }* F$ b
  10.    elif n >= 4:
    ; @6 D7 v, f  L0 p( V  K
  11.        return "Chat4.htm"
    / |% d$ y' Z- d
  12.    return "Collected "+str(n)+" of 4 fangs"
    ( J- e9 m9 L+ W$ s6 t  r( i
  13. return
Скопировать код
Метод onKill (а так же метод onTalk) имеет следующие параметры:# R9 E# @$ ~4 a$ ~+ y( o
2 l  m2 l8 C& ~7 b* H) [
+ J! B( `. a- O3 h: J, v2 x
• self – квест6 s; p" n9 q4 h8 x1 \; Z+ K
• npcId – ID NCP, которого мы должны убивать (если это метод onTalk, то ID того NCP, с которым мы должны поговорить).* w9 V3 d' ^& F% @
• st – текущее состояние игрока.
) g0 L+ B1 }3 A1 @0 C
/ H. T5 G! K9 @; k; E
% A  m) y3 |; D& h6 u; p) g
В этом методе мы проверяем и отмечаем, является ли убитый NCP keltir’ом. В основном эта проверка не нужна, т.к. у нас только KELTIR_NPC_ID.1 l1 H6 K0 Z& D& Q9 p$ y
4 Z9 w% g" c+ H! ^3 A# Z  g

6 B- D+ k1 ~! F9 u( d* ?Затем проверяем количество предметов (в данном случае количество клыков), и если их вообще нет, то возвращаем строку "Chat0.htm", если только один предмет, то возвращаем строку "Chat1.htm", если же предметов 4 или больше, то "Chat4.htm". Если строка возвращена из методов onEvent, onKill или onTalk, то сервер покажет соответствующие htm. В Chat0.htm может иметь следующий текст: «Вы не имеете ни одного клыка, возвращайтесь позже, когда соберете 4 штуки и бла, бла, бла…», в Chat1.htm может быть следующий текст: «У Вас всего 1 клык, по этому соберите еще…». В Chat4.htm – «Вы собрали необходимое количество предметов, возвращайтесь к вашему тренеру, что бы завершить квест…»
! l0 _6 d9 `$ N* j, L% F1 |7 _

% H3 o' w) e: ?Примечание: если в строка return начинается с "<html>", то будет показана страничка html с текстом, который стоит далее. Так вместо:( K2 z0 y' ^* j5 S
return "Chat4.htm"% G8 B0 z' ~% W( `

  Y& z# T9 @* Z0 ]* D) M4 M. J

+ l* d' w3 ]. M2 b; a$ [. u3 mможно поставить:
# }7 Z* [3 M/ p' L' ~9 U
  1. return "<html><body>Return to your trainer to complete the quest</body></html>"
Скопировать код
Так же если строка заканчивается без .htm или в начале нет <html>, то текст будет выведен, как системное сообщение в окне чата. В нашем случае мы сделаем так, что бы при каждом убийстве keltik выводилось системное сообщение: «Собрано N из 4-х клыков».
: W$ ~  j: I% m( L# |8 f  B
9 {4 u8 \7 k/ h

2 G' m. C" x0 m! m! zНаш код для onKill имеет один недостаток. Он будет постоянно показывать Chat0.htm, Chat1.htm и Chat4.htm, нам же необходимо, что бы Chat0.htm и Chat1.htm показывались только один раз. Как нам это сделать? С помощью переменных.
# }- B1 o, b$ k' n+ `+ ^- E1 ]5 d+ z  ~% T- P) \# i- q6 x/ p

% Q& l( v1 i& C- O4 xВ каждом квесте строки могут храниться с помощью переменных. Эти переменные сохраняются в Вашей БД. В каждом методе мы можем назначить, прочитать и удалить переменные. Давайте изменим метод onKill, так что бы каждый диалог вызывался только один раз.
5 r( O; m% I3 K: Y) B: f
  1. def onKill (self,npcId,st):
    ! e3 v8 v# o6 U+ A: ^3 b* F
  2. if npcId == KELTIR_NPC_ID:
    3 R, E8 M  ~$ Y- K# R
  3. n = getCount(st)% S2 A8 e3 G: {) }. w
  4. if n == 0:
    $ D  j  R$ o. ?# q  L6 v
  5. if st.get('chat0') == None :
    8 G( c9 f$ a  n8 [. y& S3 m2 V" U2 z
  6. st.set("chat0", "true")
    / U. x0 B; p( T: x; k& p# D
  7. return "Chat0.htm"
    1 l( s% g0 Y- S7 d+ Y! I. I
  8. elif n == 1:
    $ {0 H6 y& b$ y+ ?' V! F" p
  9. if st.get('chat1') == None :
    % L& d3 z1 m% n; D( T: p7 ]  C) T
  10. st.set("chat1", "true")2 X: n: Y, G% }0 Q) p3 f0 @
  11. return "Chat1.htm"
    ( ~" U% h5 C  W6 E2 V
  12. elif n >= 4:
    1 P. L9 g0 s" P7 p3 X  f
  13. return "Chat4.htm"( E) c  Z5 m* O3 J: x6 e  h
  14. return "Collected "+str(n)+" of 4 fangs"
    4 p* }0 O* E) G
  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.% I- Q* p) E2 l+ b2 R/ M

- |+ Q" }# O0 N  s/ J; R+ V

' E; n' h* d6 F# r/ AВот конечный рабочий вариант квеста:
* L% z; z) @; v7 O
  1. import sys
    2 |0 G4 X4 W2 M2 T0 z
  2. from net.sf.l2j.gameserver.model.quest import State
    8 k4 P5 _# t0 l
  3. from net.sf.l2j.gameserver.model.quest import QuestState
      W# {7 n/ t+ H# l# L
  4. from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest& M& Q8 m; N1 ~6 J, ]

  5. : _1 G" h3 {2 m, k' T/ p, Y
  6. KELTIR_NPC_ID = 12082
    2 m+ E8 M; x7 A6 B, b, d
  7. FANGS_ITEM_ID = 1859$ J$ h; [/ ?3 }% l0 N. ~5 W- W2 ]
  8. DROP_RATE    = 500000% D5 j, j7 _- T. |

  9. ) V  c% o6 T: f( Y0 s) w
  10. WORLD_MAP_ITEM_ID = 1665
    4 S8 c2 E/ B! z1 {$ M

  11. 4 x+ }) o9 K. e% C
  12. def getCount(st) :
    7 K: h' L0 C6 R4 |- \
  13. return st.getQuestItemsCount(FANGS_ITEM_ID), @# q1 D; T9 ~
  14. % ~2 `( Z( i' g5 V  P# n$ j. x
  15. def completed(st) :
    9 d  c0 E$ q- t- B# [: b& R2 p: i
  16. st.setState(COMPLETED)8 T8 {9 V& J  l0 [# V; r, g
  17. st.clearQuestDrops()2 d" L' G+ `. C3 y: o
  18. st.takeItems(FANGS_ITEM_ID,-1)
    # q- i: E' L) r. d8 |7 N0 }
  19. st.giveItems(WORLD_MAP_ITEM_ID,1)
      \$ `2 U2 o* h' [* Y0 L+ }* J0 v
  20. st.exitQuest(False)9 S+ p& Q# t9 m* V$ B8 Y4 f
  21. return, [' i% N) J8 ]: k+ T8 @) r  A
  22. 9 P2 i" J0 j4 ^! P0 K7 O! e" ~* X
  23. def check(st) :
    * t6 z; f1 s4 {5 Y7 K
  24. if getCount(st) >= 4 :4 t+ @; X/ ]9 }. x
  25. completed(st)
    ! t4 f" f' r1 v) Q: x7 n
  26. return/ e, `) A% F% V# n- [7 H; k* k
  27. # d; |  W% X9 Z, m4 v
  28. class Quest (JQuest):
    0 g7 Q/ P: A2 _" o( b& e3 T
  29. # `7 c  U8 ?! D
  30. def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)1 ?5 t- h% s2 k
  31. ' P" D  ?* r' }% H7 C
  32. def onEvent (self,event,st):
    4 _) O+ J$ O5 r6 ?6 q3 v! h
  33. id = st.getState()5 h/ g: T* t5 q3 Q5 x8 ^
  34. if id == CREATED : st.setState(STARTED)) O* `1 Z4 y7 \2 W+ M. t$ x
  35. elif id == COMPLETED: pass
    2 \  [: b. }# h" e' W: j
  36. elif id == STARTED : check(st)/ I5 |5 c0 `; ~1 k1 M
  37. return
    & e; l4 ~) Q3 L. h. h  a: e/ ~
  38. 9 G% G/ g7 S' F2 K) Q! d7 v; n
  39. def onKill (self,npcId,st):# O2 S2 N+ I9 x1 }4 L
  40. if npcId == KELTIR_NPC_ID:9 d9 E* n. s5 f4 h5 P, r" E( q
  41. n = getCount(st)2 T9 a6 E* t; U; Q8 F$ p
  42. if n == 0:0 {6 `7 _' l3 U" O% m1 D, I6 r
  43. if st.get('chat0') == None :- S5 {" ]* \& D1 ?, a4 a9 A
  44. st.set("chat0", "true")
      v0 n  U1 z* k; {; H5 {2 s
  45. return "Chat0.htm"
    1 n; F9 _. p/ H* ]0 ^* x
  46. elif n == 1:  Q0 r7 I) l* f. f0 A* [  S) Z2 q
  47. if st.get('chat1') == None :7 H+ W1 \" C, K# O( _! |
  48. st.set("chat1", "true")- C' p; i" d) h# R- j
  49. return "Chat1.htm"1 w$ z6 y+ A- `
  50. elif n >= 4:
    ) r* q0 M, Q2 u9 I* t
  51. return "Chat4.htm"6 Q5 x* M, ?3 a; m$ }; l
  52. return "Collect "+str(n)+" of 4 fangs"
    3 B, i  g4 T" G  h1 D' S
  53. return5 I: n7 U" e# z6 B+ J
  54. ) `: g5 o6 w# n+ |. a' J3 e" W+ @
  55. QUEST    = Quest(201, "Tutorial", "Tutorial quest")2 l/ [1 d1 z% s" H. r, E: v* B
  56. CREATED = State('Start',    QUEST)
    0 D( c$ e, [+ v  G$ m! r  ^
  57. STARTED = State('Started', QUEST)
    8 P4 e& i* @, J  d6 n1 S" t
  58. COMPLETED = State('Completed', QUEST)  M2 H1 t2 [+ \, p4 L

  59. 2 ~4 e3 F4 E6 Q' ?
  60. QUEST.setInitialState(CREATED)7 S& ^5 S) t& _
  61. QUEST.addStartNpc(7056)
    6 X# `. }+ l, T, d' K* J
  62. QUEST.addStartNpc(7012)( X/ M, R" U0 |6 g9 v8 ?4 q" x: I
  63. QUEST.addStartNpc(7009)
    # a3 f: t' A$ M2 t/ K3 K6 w; h
  64. QUEST.addStartNpc(7011)
    : a% Z' c2 Z' D' Y( b7 x) t2 O
  65. - W8 Q$ Q! I& H! v
  66. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
      j1 Z4 |) ^1 s( }# n
  67. STARTED.addKillId(KELTIR_NPC_ID); m$ h( A4 H9 g9 F5 `" G# B
  68. STARTED.addTalkId(7056)
    " i% }; w& }( s& ]
  69. STARTED.addTalkI d(7012)3 G1 ]8 a5 m  e8 j* |/ N
  70. STARTED.addTalkId(7009)- g9 A# O- n% w+ \0 @8 P8 ?: ~* b
  71. STARTED.addTalkId(7011)
Скопировать код

6 W& D' G  n" M7 \
* o# |; A4 Y5 J: f
Чтобы ответить, вам надо авторизироваться в системе Вход | Зарегистрироваться

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

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

638638758

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

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

admin@artace.ru Онлайн

QR-код

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