Top.Mail.Ru

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

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

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

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

x
Хроники        Interlude
# u0 }6 J" f& J; b  uСборка        L2j
! x# B, b; j$ \/ zОбратите внимание: в файле htm стартового NCP обязательно должна быть ссылка на квест:
0 Q" b7 o0 g; K" g8 D
  1. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста:
: j0 g7 Z' ?& t
6 R: F" g/ k( R
  1. if getCount(st) >= 4 :
    7 `9 m# D0 u/ X3 M
  2. completed(st)
    6 T' V: B( ]- [$ b" e
  3.   return
    6 t: j) }1 q# |- u

  4. , p4 b  F9 t0 y2 U! @8 f. w
  5. class Quest (JQuest):0 n) m  A2 }; S* j' ^" A
  6.   def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)
    / S1 M2 q# k/ o% f% M
  7.   def onEvent (self,event,st):1 t& o0 t. s+ J9 `, m
  8. id = st.getState()
    6 V; D" K" f+ H8 P  O8 ?
  9. if   id == CREATED  : st.setState(STARTED)
    ) ?3 C5 }. C3 R- x& G9 r
  10. elif id == COMPLETED: pass
    ' n) y- l" z' p
  11. elif id == STARTED  : check(st)
    6 R8 ]  @1 A9 {- [! M4 i9 g# j" U
  12. return
    + {4 J0 S2 }0 B0 u$ J' [; W; ]
  13. 9 [6 {+ ]! B# {3 y0 \
  14. QUEST     = Quest(201,"Tutorial", "Tutorial quest")7 w" s. ]' ]3 j* i: O# C
  15. CREATED   = State('Start',     QUEST)
    ; Q  `/ w6 a: F& l! A
  16. STARTED   = State('Started',   QUEST)% D- o! r1 o* G' r8 K& o' J
  17. COMPLETED = State('Completed', QUEST)8 I, i" @7 a( N" \& j

  18. 1 b% y6 }8 L* ~4 e( k4 X  `
  19. QUEST.setInitialState(CREATED)2 G6 u( l6 Y4 P  B
  20. QUEST.addStartNpc(7056)+ d& T7 k( D3 z2 b
  21. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Теперь рассмотрим, как это работает.
+ h& Z1 ~3 ]% gИгрок подходит к начальному NCP (в данном случае 7056), нажимает на «Quest». Квест будет создан и состояние квеста перейдет к CREATED и игроку будет показана страничка Start.htm с описанием квеста. Тогда метод onEvent, поле открытия странички Start.htm переведет состояние квеста в STARTED и игроку будет показана страничка Started.htm, где будет опсание того, как найти keltirs и .т.д.% `* ~3 q" o7 a

8 k6 X7 k$ s/ D3 [, b

) O/ G+ t& \4 y! WПри состоянии STARTED будет зарегистрирован дроп «fangs» при убийстве keltirs. Игрок может вернуться к стартовому NCP и спросить о квесте – метод onEvent будет вызван снова. Если у игрока не хватает необходимого количества предметов, то метод check() не переведет квест в следующее состояние и Started.htm будет показана снова. Но если игрок собрал необходимее количество предметов (в данном случае 4 клыка), то метод check() вызовет метод completed() который переведет квест в новое состояние COMPLETED, заберет все клыки, даст карту мира, т.к. это награда за квест, покажет Completed.htm и завершит квест.
( _( ~$ K3 s8 F: u, n) K
  z* z6 f9 y9 o  s/ @

3 _+ ]* y$ H- U  [* X. ~- d8 Y) w  e' zТеперь давайте сделаем наш квест более похожим на то, что он должен из себя представлять.5 p1 I4 C7 r+ X  ~8 F5 ]
Прежде всего у нас есть 3 метода для объявления их в Яве – onTalk, onKill и onEvent. Если методы onTalk и onKill не объявлены, то за них все будет делать метод onEvent, т.е. определять квестовых монстров и вызывать диалоги NCP. Есть примечание, методы onTalk и onKill будут вызывать только диалоги с NCP в зависимости от текущего состояния квеста. Метод onKill будет вызываться только тогда, когда мы убиваем квестового монстра.
7 @/ Z; |) g6 K+ u
( H, ?7 S; @4 u8 y2 Y5 \1 F% w: o

. O7 j% [% q, n; G% B) L; E/ UДавайте рассмотрим как вызывается метод onKill при убийстве keltir в состоянии квеста STARTED:
7 t; H$ T% }( K* n: y$ w
  1. STARTED.addKillId(KELTIR_NPC_ID)
Скопировать код
и метод onKill в классе Quest:: B' t9 T1 Y9 @
6 k# g5 w1 K8 P7 u; C
  1. class Quest (JQuest):
    9 s1 p6 s. n9 f  }/ F
  2.   ...
    ( C9 d3 Y! U+ }4 c4 W
  3.   def onKill (self,npcId,st):
    2 W! U$ S) X; w$ V
  4. if npcId == KELTIR_NPC_ID:" X. x8 K  K( E# i
  5.    n = getCount(st)4 B6 W& I0 \( O2 y8 p9 ^
  6.    if   n == 0:
    ; z# ?0 F2 k% S; u
  7.        return "Chat0.htm"
    $ `; w& l; \6 r" o; T4 u' ~! g% e
  8.    elif n == 1:
    , _/ v: F4 j& B* V+ R
  9.        return "Chat1.htm"
    8 r) f8 L8 B! u0 k2 H
  10.    elif n >= 4:: U' }' f2 F$ M$ j" W, c- L6 C
  11.        return "Chat4.htm"
    * @8 {' p1 h5 ?* e7 }- D0 R" h  B
  12.    return "Collected "+str(n)+" of 4 fangs"/ {/ T2 H2 l5 |" M6 A$ }
  13. return
Скопировать код
Метод onKill (а так же метод onTalk) имеет следующие параметры:
' C4 d* B9 b0 `3 M) v3 \- a* W7 x, R: F6 K0 a3 `9 h7 I9 x2 Q

1 u  K% N+ [3 _6 Y1 Y• self – квест: x5 t/ A0 C+ a7 f% R" S1 e! b' K2 d' `
• npcId – ID NCP, которого мы должны убивать (если это метод onTalk, то ID того NCP, с которым мы должны поговорить).
9 ~6 h0 x! v" {6 O" h• st – текущее состояние игрока.# B: C1 o, F5 F/ I/ Y
. q, t5 [! [' [& X1 z  K7 E; o
; O9 s5 ?2 @6 D' p5 ]( t+ m1 L/ y
В этом методе мы проверяем и отмечаем, является ли убитый NCP keltir’ом. В основном эта проверка не нужна, т.к. у нас только KELTIR_NPC_ID.
7 R% b/ k7 e" U  N9 i% G
/ n1 n- n; k8 M5 ]; ^0 H  z

$ y; {; W# c( k) l/ u$ a& d6 iЗатем проверяем количество предметов (в данном случае количество клыков), и если их вообще нет, то возвращаем строку "Chat0.htm", если только один предмет, то возвращаем строку "Chat1.htm", если же предметов 4 или больше, то "Chat4.htm". Если строка возвращена из методов onEvent, onKill или onTalk, то сервер покажет соответствующие htm. В Chat0.htm может иметь следующий текст: «Вы не имеете ни одного клыка, возвращайтесь позже, когда соберете 4 штуки и бла, бла, бла…», в Chat1.htm может быть следующий текст: «У Вас всего 1 клык, по этому соберите еще…». В Chat4.htm – «Вы собрали необходимое количество предметов, возвращайтесь к вашему тренеру, что бы завершить квест…»' ^% v9 J9 ]5 D0 ]) ?

7 F2 Z: `% i) T) A
+ {1 u! W: |1 j) ~" U" E1 U# K
Примечание: если в строка return начинается с "<html>", то будет показана страничка html с текстом, который стоит далее. Так вместо:# W) a7 y  Y6 h% h9 i5 C2 `
return "Chat4.htm"3 s. W8 F8 |' r
  h+ [1 ?- Y8 l3 F+ q6 g* i1 R; T- Y

. u% v* J! F# `, D5 _6 Oможно поставить:
6 g% i% Q- m- O2 }
  1. return "<html><body>Return to your trainer to complete the quest</body></html>"
Скопировать код
Так же если строка заканчивается без .htm или в начале нет <html>, то текст будет выведен, как системное сообщение в окне чата. В нашем случае мы сделаем так, что бы при каждом убийстве keltik выводилось системное сообщение: «Собрано N из 4-х клыков».- _: ?" @" j5 T* G' k8 [

  Z& _; r; w' a; m7 ]

6 z5 m0 a: R1 `$ WНаш код для onKill имеет один недостаток. Он будет постоянно показывать Chat0.htm, Chat1.htm и Chat4.htm, нам же необходимо, что бы Chat0.htm и Chat1.htm показывались только один раз. Как нам это сделать? С помощью переменных.
- b; e* U( f* N* [$ v3 [! B) u2 S+ s! b: E, Z4 D- I
' a2 E1 O' x) |/ R
В каждом квесте строки могут храниться с помощью переменных. Эти переменные сохраняются в Вашей БД. В каждом методе мы можем назначить, прочитать и удалить переменные. Давайте изменим метод onKill, так что бы каждый диалог вызывался только один раз.
6 g- q. x4 r: M  f& e4 ]3 ^
  1. def onKill (self,npcId,st):
    3 L* g) v2 i0 v9 W
  2. if npcId == KELTIR_NPC_ID:
    3 Y4 {$ }4 O2 J. l" _% ?) e
  3. n = getCount(st): z6 _+ Z% n# r2 L: @+ [# `
  4. if n == 0:
    ; w; S" N& \- A' A7 X! _/ Y8 h
  5. if st.get('chat0') == None :
    9 x# ?2 ^7 l+ r# m( X) Q
  6. st.set("chat0", "true"), N* O9 ]4 z/ A4 J+ h* }3 `1 B
  7. return "Chat0.htm"
    8 @  B. m- D* c6 }6 c4 e
  8. elif n == 1:: {. K6 ^; `, p4 K
  9. if st.get('chat1') == None :. Q4 e  r* K2 P3 T! {$ m( G4 o
  10. st.set("chat1", "true")
    - i; q0 K) f5 H8 h+ Q. s
  11. return "Chat1.htm"
    7 F0 d5 T$ E, ]( k1 I) D$ A% p
  12. elif n >= 4:4 [! U! l- D9 Q# v
  13. return "Chat4.htm"+ S9 F! @+ V: }( K; y
  14. return "Collected "+str(n)+" of 4 fangs"/ W5 w3 o! @. e8 _
  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.
: F6 n% D7 i' i  l% h- I6 X$ R) B7 w3 ~

6 b/ X" L( I* b3 @3 s6 q; v: aВот конечный рабочий вариант квеста:2 Q* K% ^+ w# d0 |- m# {' s) }
  1. import sys
    4 P' ^5 P7 Y7 B
  2. from net.sf.l2j.gameserver.model.quest import State" `5 ^+ t7 n1 D0 R! T
  3. from net.sf.l2j.gameserver.model.quest import QuestState
    9 S8 I" B; i' d& G3 O. @8 X. w
  4. from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest  }/ x& f) I# z3 v

  5. ( Z; _, ~" L- Z" r
  6. KELTIR_NPC_ID = 12082
    0 u' c1 D) H: n4 X: y6 D# I( z
  7. FANGS_ITEM_ID = 1859% `, x0 |# O# p! ~! q4 l5 T' g1 v) O
  8. DROP_RATE    = 500000
    ' g& O. c9 C7 w( ]  |. x& y

  9. # y& I) [5 |3 D6 g
  10. WORLD_MAP_ITEM_ID = 16657 Y$ h4 M7 Q7 f5 N' _2 K- H* t

  11. $ [- D9 @! |2 f( g, G# |
  12. def getCount(st) :) I" G/ f! e# K
  13. return st.getQuestItemsCount(FANGS_ITEM_ID)
    % b+ v- R5 S% F- [: \

  14. - v  G3 b- r( v2 c2 F  g" u9 ]) Y
  15. def completed(st) :% K0 l. e6 }# g: H, ^
  16. st.setState(COMPLETED)# w6 c6 N8 n6 P7 D" S3 d# W
  17. st.clearQuestDrops()) e& Z# m4 K, i) L' ?/ E. z
  18. st.takeItems(FANGS_ITEM_ID,-1)
    4 C( O) L" r- ^( [8 H0 o2 O* U
  19. st.giveItems(WORLD_MAP_ITEM_ID,1)
    & Z4 w: r6 e/ }/ G
  20. st.exitQuest(False)% p, V' ^; O5 e! Y  @  x$ @
  21. return
    9 J8 G# {% P% ?, t, {

  22. $ G" o6 _7 K8 M! L7 b6 t7 {# V
  23. def check(st) :
    , c/ n, C: G8 G9 o  X/ P
  24. if getCount(st) >= 4 :  [- E7 l9 R9 g8 J+ p! u; _8 Z
  25. completed(st)
    1 r" I9 a! v, W( W
  26. return2 B/ l; b5 Z& u; ]9 r6 T" h
  27. , z3 b; j+ @& ?0 l* E
  28. class Quest (JQuest):
    6 r7 L% N; l2 s
  29. 6 W- P  j' a! B5 v1 O% d4 T, ^
  30. def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr), S4 j0 E( j4 f( u3 E
  31. ; E8 x( A7 z3 s1 ?0 F8 y6 ]
  32. def onEvent (self,event,st):
    # x, j: Z: [( d& S+ z, `8 R$ o
  33. id = st.getState()
    5 A. {* S& e3 G! W# z. O
  34. if id == CREATED : st.setState(STARTED)
      M7 G3 c0 O7 i  E# {- S
  35. elif id == COMPLETED: pass* L1 B& b* m" f4 w! ^6 O
  36. elif id == STARTED : check(st)
    ( I% P, L/ X. M1 Z3 }* l
  37. return/ P  H$ b8 `1 d

  38. ( ?3 w) h& {% j
  39. def onKill (self,npcId,st):
    . y2 W) }5 p& m& V4 T$ P
  40. if npcId == KELTIR_NPC_ID:
    ( M# o6 i: m$ c3 G, g
  41. n = getCount(st)
    ( D& h. A8 @- S) G% J* F
  42. if n == 0:
    0 Y( C6 ^  Z6 s+ v" `( n* F
  43. if st.get('chat0') == None :: x' o+ ?/ c+ ~& M( Y! x9 L4 U) v
  44. st.set("chat0", "true")" U. @( x! [8 W" m: ~  j3 Q+ R
  45. return "Chat0.htm"
    : V( D8 E" w7 e/ K5 @
  46. elif n == 1:
    " }5 o* i* o0 }2 |  N1 w
  47. if st.get('chat1') == None :! C, @2 ?. p2 s9 g' P* O* {; C2 y% T
  48. st.set("chat1", "true")8 z, p6 Y  S3 z1 h
  49. return "Chat1.htm"
    2 R) k0 C& n& Y2 B/ z; ~
  50. elif n >= 4:
    0 z& h7 z' T. t. x# G
  51. return "Chat4.htm"
    : V% W4 o, r3 r: y% J3 d; t3 ]
  52. return "Collect "+str(n)+" of 4 fangs"
    ' X6 I2 j  i0 y( q  |: h
  53. return
    / D5 |: A5 J: Q6 O

  54. & ^$ _6 G; J1 d$ n, p* B
  55. QUEST    = Quest(201, "Tutorial", "Tutorial quest")* P3 V8 N* ?% G6 J/ E& a! V
  56. CREATED = State('Start',    QUEST)( p3 Y- W8 m* c1 R, k' h
  57. STARTED = State('Started', QUEST)8 q% i4 X6 v% g$ b6 f5 D
  58. COMPLETED = State('Completed', QUEST)
    , d- _# C+ N! B* }2 P; q4 N
  59. # i  D. {* u- ^- {$ B
  60. QUEST.setInitialState(CREATED); l& d* G: d9 r. ~8 V6 D3 \
  61. QUEST.addStartNpc(7056)- b) Z, v, U/ ?* b6 E
  62. QUEST.addStartNpc(7012)" x' E4 v6 J4 }& |
  63. QUEST.addStartNpc(7009)7 X6 D) B1 n3 Q, A& R. o
  64. QUEST.addStartNpc(7011); Q7 T7 e+ g0 p  ?7 B, {9 m

  65. ) d' v2 `+ b" H$ N
  66. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)+ [  D" S; x* c- v# o
  67. STARTED.addKillId(KELTIR_NPC_ID)
    + H, R; X& J& i( ]. Q4 }. K
  68. STARTED.addTalkId(7056). d5 \  C4 Q. ^! ~
  69. STARTED.addTalkI d(7012)
    # S1 @9 ]/ O' K: |9 t$ f  X. K: i
  70. STARTED.addTalkId(7009), {7 e% \6 h- K4 ?, |: S. g
  71. STARTED.addTalkId(7011)
Скопировать код

( b) s1 }. c! A* ~) T- L! q* {  W5 G6 y( w. R
Чтобы ответить, вам надо авторизироваться в системе Вход | Зарегистрироваться

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

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

638638758

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

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

admin@artace.ru Онлайн

QR-код

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