Top.Mail.Ru

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

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

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

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

x
Хроники        Interlude. }4 N6 O- \/ B6 n  {( V
Сборка        L2j
2 O* V" N+ R4 g+ a7 ]# @2 g( uОбратите внимание: в файле htm стартового NCP обязательно должна быть ссылка на квест:
% }' |5 |% q' b
  1. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста:* d3 x3 T  B7 e! E9 H  L: u* ?
+ M" Q7 K" ~' l8 V/ X8 K$ @
  1. if getCount(st) >= 4 :0 q5 f  e8 o6 h& r1 p: R' q
  2. completed(st)
    ; n- J( [$ W" O+ A  Z" q
  3.   return. e1 u2 U1 o% r, F9 g
  4. $ _$ I% b% Q1 l; A( @5 v- t& [
  5. class Quest (JQuest):' S! v, l% f1 U5 {
  6.   def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)7 E- A& o" ]/ U  `5 U+ Y
  7.   def onEvent (self,event,st):
    / x7 [, c' B9 d$ D9 L$ c
  8. id = st.getState()0 d1 j+ c+ `% L* v# w. x
  9. if   id == CREATED  : st.setState(STARTED)
    ; p' y  b* S3 M- x+ O9 f2 X4 ]
  10. elif id == COMPLETED: pass  z6 K( ^: L* j) d
  11. elif id == STARTED  : check(st)8 N7 O" [0 }/ W1 ?+ b  l
  12. return
    , Q- x- M7 q7 d. V

  13.   d  X* M1 |) m1 v* w4 i
  14. QUEST     = Quest(201,"Tutorial", "Tutorial quest")
    ( \; M3 N$ C! p6 h/ a: z1 Y
  15. CREATED   = State('Start',     QUEST)
    & d1 P6 Z# C% T$ t" C
  16. STARTED   = State('Started',   QUEST)5 J' _- }/ Q3 J7 U/ e. ?$ N
  17. COMPLETED = State('Completed', QUEST)+ B, U$ A) G# p% `- J/ \+ M

  18. 5 Z; U* g* U, f' n! T6 v
  19. QUEST.setInitialState(CREATED)0 {( b" e  S- Z$ j0 H5 ^
  20. QUEST.addStartNpc(7056)
      ]3 T2 d; ^9 }# u+ y
  21. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Теперь рассмотрим, как это работает.
5 A3 M6 i2 L( l0 H+ q3 z4 I8 A" yИгрок подходит к начальному NCP (в данном случае 7056), нажимает на «Quest». Квест будет создан и состояние квеста перейдет к CREATED и игроку будет показана страничка Start.htm с описанием квеста. Тогда метод onEvent, поле открытия странички Start.htm переведет состояние квеста в STARTED и игроку будет показана страничка Started.htm, где будет опсание того, как найти keltirs и .т.д.: f( x' t5 x* Z4 e  u2 S  d

2 t6 U6 ~, b- k/ L! O
0 j$ i* d. B9 b6 J
При состоянии STARTED будет зарегистрирован дроп «fangs» при убийстве keltirs. Игрок может вернуться к стартовому NCP и спросить о квесте – метод onEvent будет вызван снова. Если у игрока не хватает необходимого количества предметов, то метод check() не переведет квест в следующее состояние и Started.htm будет показана снова. Но если игрок собрал необходимее количество предметов (в данном случае 4 клыка), то метод check() вызовет метод completed() который переведет квест в новое состояние COMPLETED, заберет все клыки, даст карту мира, т.к. это награда за квест, покажет Completed.htm и завершит квест.# Z3 c! s% u* y& F

; M& A0 u9 |7 d' b0 B* w9 i

; j1 Y% [' G/ [* c: ]+ @( y. IТеперь давайте сделаем наш квест более похожим на то, что он должен из себя представлять.
, D' A6 y' {. v1 I5 [Прежде всего у нас есть 3 метода для объявления их в Яве – onTalk, onKill и onEvent. Если методы onTalk и onKill не объявлены, то за них все будет делать метод onEvent, т.е. определять квестовых монстров и вызывать диалоги NCP. Есть примечание, методы onTalk и onKill будут вызывать только диалоги с NCP в зависимости от текущего состояния квеста. Метод onKill будет вызываться только тогда, когда мы убиваем квестового монстра.
; U& Q$ ]& z; c' n7 s( j9 p7 ~5 }$ t0 c' C% [
) |5 r+ V/ v( K% n
Давайте рассмотрим как вызывается метод onKill при убийстве keltir в состоянии квеста STARTED:
! o7 y! r' b/ N5 D# e6 O) L: N
  1. STARTED.addKillId(KELTIR_NPC_ID)
Скопировать код
и метод onKill в классе Quest:( g1 k7 ?. `( @/ P* M; q0 K

/ [2 Y* m' b# @7 V4 o3 q2 q  h; C/ A
  1. class Quest (JQuest):$ A# _3 T7 r! ^2 g. m
  2.   ...
    3 T$ w6 @$ K2 ^( Z5 ^& J- f. [
  3.   def onKill (self,npcId,st):2 R2 t: F* \, x& p& `8 K( d
  4. if npcId == KELTIR_NPC_ID:3 B% d" H$ n" m1 }/ F* E' a1 p6 M
  5.    n = getCount(st)! J9 d. t  M1 A' u* j: p9 m
  6.    if   n == 0:( r2 \4 R8 g, N6 j+ J
  7.        return "Chat0.htm"* I& G3 v) j( I+ X: i( [' L9 e
  8.    elif n == 1:
    9 F  t) _) O4 J6 e5 m4 U4 m; p. |% D
  9.        return "Chat1.htm"/ l3 x6 Y( b3 `
  10.    elif n >= 4:  y( e% L, J! M# c/ S9 t9 X
  11.        return "Chat4.htm"
    1 N- |4 M1 H5 }' \9 \7 Q4 Q
  12.    return "Collected "+str(n)+" of 4 fangs"1 W7 b' Z" @# k3 z4 b. s+ H( A
  13. return
Скопировать код
Метод onKill (а так же метод onTalk) имеет следующие параметры:
; t9 }0 }! _( \; X+ O
/ U3 ]) h' J: R* h/ F+ ?
( `2 c& e3 [3 ]! j3 u( l
• self – квест" M3 C+ [( z7 {- Y" l
• npcId – ID NCP, которого мы должны убивать (если это метод onTalk, то ID того NCP, с которым мы должны поговорить).
  W" p3 ]+ q/ q2 S• st – текущее состояние игрока.5 Y; A9 R3 F$ x' n. Q9 V
, P+ G5 `! v: o9 [! Z& Z& O
) l5 N8 X) C7 o- }# d
В этом методе мы проверяем и отмечаем, является ли убитый NCP keltir’ом. В основном эта проверка не нужна, т.к. у нас только KELTIR_NPC_ID.2 U! y6 r- o& L6 Y3 N+ n
* e( \& D! N$ G7 e
0 r% v. ^* A$ a9 Y% O( c) E
Затем проверяем количество предметов (в данном случае количество клыков), и если их вообще нет, то возвращаем строку "Chat0.htm", если только один предмет, то возвращаем строку "Chat1.htm", если же предметов 4 или больше, то "Chat4.htm". Если строка возвращена из методов onEvent, onKill или onTalk, то сервер покажет соответствующие htm. В Chat0.htm может иметь следующий текст: «Вы не имеете ни одного клыка, возвращайтесь позже, когда соберете 4 штуки и бла, бла, бла…», в Chat1.htm может быть следующий текст: «У Вас всего 1 клык, по этому соберите еще…». В Chat4.htm – «Вы собрали необходимое количество предметов, возвращайтесь к вашему тренеру, что бы завершить квест…»
' J6 y& p2 r, W3 @  q+ v
# `* q9 l0 v( x3 H& U4 G

, t6 ?+ F- ^, C+ \- C& BПримечание: если в строка return начинается с "<html>", то будет показана страничка html с текстом, который стоит далее. Так вместо:
/ D+ D: m2 E, \6 \7 @" ^7 q* x! dreturn "Chat4.htm"
+ n& ~) B0 a* `/ l( N+ G- M6 s
$ D1 P& n6 g' B
$ a  L+ \1 D$ h% L9 N
можно поставить:
. G3 \: m: d( Y; N
  1. return "<html><body>Return to your trainer to complete the quest</body></html>"
Скопировать код
Так же если строка заканчивается без .htm или в начале нет <html>, то текст будет выведен, как системное сообщение в окне чата. В нашем случае мы сделаем так, что бы при каждом убийстве keltik выводилось системное сообщение: «Собрано N из 4-х клыков».3 C$ q3 U3 l; y: C8 a
* E0 J, `* i- N' M8 s

6 H$ ?- Y: f4 JНаш код для onKill имеет один недостаток. Он будет постоянно показывать Chat0.htm, Chat1.htm и Chat4.htm, нам же необходимо, что бы Chat0.htm и Chat1.htm показывались только один раз. Как нам это сделать? С помощью переменных.
; f  h1 y! W4 t0 E8 r, a, W
: B2 w& y+ {6 ~2 P
1 O! F1 `0 s5 J
В каждом квесте строки могут храниться с помощью переменных. Эти переменные сохраняются в Вашей БД. В каждом методе мы можем назначить, прочитать и удалить переменные. Давайте изменим метод onKill, так что бы каждый диалог вызывался только один раз., X7 J% B- m' R$ P8 }
  1. def onKill (self,npcId,st):
    ) N+ h! O- ]1 b$ C0 `& w* i. {% s5 s
  2. if npcId == KELTIR_NPC_ID:
    & Y/ s+ \0 U8 h" l( m# Y% q
  3. n = getCount(st)
    & E+ u  [$ }  Y9 T# u7 X. N" R' P" K
  4. if n == 0:
    1 r9 O% e, {& f6 L2 Z! P
  5. if st.get('chat0') == None :
    " n, P' y* @% U' |+ p  c
  6. st.set("chat0", "true")5 Q' d+ ]% ~# L8 I2 O' W: g
  7. return "Chat0.htm"
    5 O3 J# @( T) E( K& e
  8. elif n == 1:" Q8 \8 f$ D- D, B
  9. if st.get('chat1') == None :
    * B" r3 j( m- J- R
  10. st.set("chat1", "true"), _# [2 o# O1 l
  11. return "Chat1.htm"
    5 d% z( S+ _2 \- L& i
  12. elif n >= 4:
    ( g& n3 [' M2 {9 G
  13. return "Chat4.htm"4 w& A- O: H* e1 h4 I( n- _( w
  14. return "Collected "+str(n)+" of 4 fangs"1 H$ B" p# [# @4 i8 a
  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.; O; q, D# K+ g" L2 F" z
: m) M; B7 m; X; x0 J7 @0 U1 w

3 f+ V# ^! z$ Y' `) A! ?Вот конечный рабочий вариант квеста:$ Q' f3 F$ n2 M) _" J. P  y
  1. import sys
    0 _% W2 d0 o' }) i* O
  2. from net.sf.l2j.gameserver.model.quest import State' x, g; c1 m. g: @6 m+ |1 J8 u! m
  3. from net.sf.l2j.gameserver.model.quest import QuestState& y& B& T& M7 j$ Z! t
  4. from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest
    / q6 |+ K7 p8 [( t( @+ w

  5. + c6 F* o* Q+ ~" u$ Y
  6. KELTIR_NPC_ID = 12082
    , `% ^' t- J& M; {/ C
  7. FANGS_ITEM_ID = 1859" r' k3 _9 R  s' o9 {
  8. DROP_RATE    = 500000
    + D2 i2 _3 m  I2 b6 B

  9. - A0 `6 Q6 x$ C6 e8 c
  10. WORLD_MAP_ITEM_ID = 1665
    # G( _, n# Q4 G7 b% Y0 k

  11. " V! @9 ^: {3 f/ S' n
  12. def getCount(st) :
      l" P1 C8 W" ?8 p6 T3 _1 o! Y0 R
  13. return st.getQuestItemsCount(FANGS_ITEM_ID)( |( X; F+ I5 H; t4 M* f4 m
  14.   n3 B, q8 `/ C/ i, v0 O% y7 b# O
  15. def completed(st) :1 z3 Z0 F6 ^* I8 z+ q
  16. st.setState(COMPLETED)
    ! w" z% G# v% R9 v& ~' R9 ~- `
  17. st.clearQuestDrops()+ t; R0 S% G) K" O% F6 ?# k
  18. st.takeItems(FANGS_ITEM_ID,-1)
    ) q4 @- S6 i7 K$ \
  19. st.giveItems(WORLD_MAP_ITEM_ID,1)
    0 g2 k3 T7 F# N8 R' K' [$ E
  20. st.exitQuest(False)8 A! x* v9 z: Q- B
  21. return3 R' c" v' Z" N4 E, c8 g( m% V

  22. : I8 S% Y8 J. T  T. ]/ J9 z
  23. def check(st) :5 ]1 n% S# y5 I# q
  24. if getCount(st) >= 4 :% s( J3 ?# m. U# V; r
  25. completed(st)7 B2 R: ]" M' L" w
  26. return
    8 s2 A2 ^8 X1 U( U3 ^* B! f

  27. : Q0 ^+ p7 N3 S# e6 A& {
  28. class Quest (JQuest):
    # {" [! z. A( Z0 P

  29. ( `! `* p' F2 y" }" v
  30. def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)
    ! G+ b( D* L4 [2 u; g8 q

  31. 2 Y# J2 |2 E0 r4 q6 U( i
  32. def onEvent (self,event,st):
    + U1 y) V4 U5 [. |' b' P
  33. id = st.getState()
    + z8 r2 Q) F+ M2 @2 k
  34. if id == CREATED : st.setState(STARTED)) D8 \( J: c- j
  35. elif id == COMPLETED: pass/ t2 W1 x! f/ A; t5 f* K
  36. elif id == STARTED : check(st)! \7 Y6 Z2 f$ E0 ^; n4 v9 E; Q
  37. return
    ' t5 R$ r7 v( c, |3 X( V1 {/ d$ e& t

  38. ' E! J0 b8 O! j, P
  39. def onKill (self,npcId,st):
    % y, s& N; |) q3 ^9 Z
  40. if npcId == KELTIR_NPC_ID:1 c# ?$ s+ c& {5 Q! m9 ~6 A
  41. n = getCount(st)
    : H, w1 T  \" ?) C3 [$ }  r
  42. if n == 0:
    4 ]; h0 K' F3 i/ V- o. ]5 g; t
  43. if st.get('chat0') == None :5 \( D/ Q9 ^% E% Q
  44. st.set("chat0", "true")" X! M8 p) v- e! _
  45. return "Chat0.htm"
    0 }" j8 j+ F" |; C9 B* F& `
  46. elif n == 1:7 d% O; A, X: H  h/ e5 t
  47. if st.get('chat1') == None :! ^3 q$ O2 ]2 K+ q/ Q
  48. st.set("chat1", "true")
    ( d  {1 l7 r+ q+ j4 ?. G6 d
  49. return "Chat1.htm"5 X+ v# W& ]* v1 X- q5 m
  50. elif n >= 4:% T' n# s" H2 b6 K. E
  51. return "Chat4.htm"' R2 }& B- P* i9 P
  52. return "Collect "+str(n)+" of 4 fangs") \. _7 _! R) f4 U& i' a! Q
  53. return
    - }1 L6 Z- Y4 W9 H5 ~
  54. 6 V( P9 x3 K; {, K+ `# K
  55. QUEST    = Quest(201, "Tutorial", "Tutorial quest"): i+ G: g- n; A7 I4 B; B
  56. CREATED = State('Start',    QUEST)5 I1 o% ?, ?5 \, R
  57. STARTED = State('Started', QUEST)
    ! S+ `' A2 N/ ?* C2 R
  58. COMPLETED = State('Completed', QUEST)
    1 M4 C9 J( Q/ y' h  b6 }
  59. " l! J5 n  z& O) E
  60. QUEST.setInitialState(CREATED), z. ~7 Z, \1 l3 e7 w
  61. QUEST.addStartNpc(7056)
    " i0 |0 g& p: A
  62. QUEST.addStartNpc(7012)
    + R+ K/ X9 @  v) R8 @
  63. QUEST.addStartNpc(7009); j1 o1 E6 |+ C* M' O% @- p
  64. QUEST.addStartNpc(7011)" p9 C2 j0 K1 `" ~8 D

  65. % E6 t7 X7 s; D) w: y9 N
  66. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
    ( T! V% a' V$ T7 G
  67. STARTED.addKillId(KELTIR_NPC_ID)
    % r8 ?* @3 G/ m6 V0 I
  68. STARTED.addTalkId(7056)5 j5 d% T8 F7 O; B. t6 a; {1 ]
  69. STARTED.addTalkI d(7012)1 `3 e" m+ N4 x: P3 _9 }* |
  70. STARTED.addTalkId(7009)
    . V' s  ^7 m1 T5 C$ s/ V0 \
  71. STARTED.addTalkId(7011)
Скопировать код
) w) j4 F- g/ n6 Y5 k6 H( j
, L: i5 u' x: Z1 V9 r
Чтобы ответить, вам надо авторизироваться в системе Вход | Зарегистрироваться

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

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

638638758

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

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

admin@artace.ru Онлайн

QR-код

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