artace.ru - творческий сектор

Название: Создаём собственные квесты (часть 2) [Версия для печати]

Автор: admin    Время: 2024-9-17 19:36
Название: Создаём собственные квесты (часть 2)
Хроники        Interlude
9 T* }" L8 q  z9 [1 V. }Сборка        L2j3 j. m3 n; c9 l0 U& n
Обратите внимание: в файле htm стартового NCP обязательно должна быть ссылка на квест:
3 R; k2 E/ R2 c5 z$ H8 j& e) ]7 ?/ U
  1. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста:+ G+ k# W! n! C" k

& t' S* r* B0 G" o' b1 E* C1 @
  1. if getCount(st) >= 4 :
    6 }. I, N6 ^9 L
  2. completed(st)
    5 Y" a6 ?% _; u- W+ I* n+ r
  3.   return
    * I5 s5 P& M; V

  4. 4 i5 J! x/ t# f! d  o8 i
  5. class Quest (JQuest):4 z9 k/ k, v1 w
  6.   def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr): {7 y6 l8 F9 U
  7.   def onEvent (self,event,st):9 @4 T3 U. p$ Y1 g% j4 x& u( T
  8. id = st.getState()7 C. q, Z) j8 @; v" d  H
  9. if   id == CREATED  : st.setState(STARTED)+ a* g( S; Q7 h3 P/ Y/ j1 e6 X9 Q
  10. elif id == COMPLETED: pass7 N& n, \8 `- \: m
  11. elif id == STARTED  : check(st)
    / d7 i8 r  I4 `/ Z7 O: K6 @$ `7 Z) |
  12. return
    ; X3 B6 w) u1 i' I
  13. $ O) P' k8 l  c; V
  14. QUEST     = Quest(201,"Tutorial", "Tutorial quest")0 b& h" W5 h/ A5 w' x( l. K0 |
  15. CREATED   = State('Start',     QUEST)
    , ~6 b6 _3 D1 S/ V7 _: t
  16. STARTED   = State('Started',   QUEST)% \6 ^" R: h- w6 E+ e
  17. COMPLETED = State('Completed', QUEST)# l* G8 q. r, r6 b

  18. 8 F/ c0 z% @7 R4 Q
  19. QUEST.setInitialState(CREATED)
    , o( k8 g- J8 _) h4 Q
  20. QUEST.addStartNpc(7056)7 X* f6 f  u' ~  @: k
  21. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Теперь рассмотрим, как это работает.. v# {+ G0 Q* d" `
Игрок подходит к начальному NCP (в данном случае 7056), нажимает на «Quest». Квест будет создан и состояние квеста перейдет к CREATED и игроку будет показана страничка Start.htm с описанием квеста. Тогда метод onEvent, поле открытия странички Start.htm переведет состояние квеста в STARTED и игроку будет показана страничка Started.htm, где будет опсание того, как найти keltirs и .т.д.
* G$ I- h+ }2 o) R; q9 y/ r' k
5 ]/ f0 P" I  W2 r: v$ _

9 [6 B' C' w5 ~+ S4 xПри состоянии STARTED будет зарегистрирован дроп «fangs» при убийстве keltirs. Игрок может вернуться к стартовому NCP и спросить о квесте – метод onEvent будет вызван снова. Если у игрока не хватает необходимого количества предметов, то метод check() не переведет квест в следующее состояние и Started.htm будет показана снова. Но если игрок собрал необходимее количество предметов (в данном случае 4 клыка), то метод check() вызовет метод completed() который переведет квест в новое состояние COMPLETED, заберет все клыки, даст карту мира, т.к. это награда за квест, покажет Completed.htm и завершит квест.6 {5 \4 q( U7 b

4 ^5 W  v! [) G) \+ ^* s

7 g9 |+ z% H, fТеперь давайте сделаем наш квест более похожим на то, что он должен из себя представлять.8 |' W6 e) Q& M8 a1 P( W
Прежде всего у нас есть 3 метода для объявления их в Яве – onTalk, onKill и onEvent. Если методы onTalk и onKill не объявлены, то за них все будет делать метод onEvent, т.е. определять квестовых монстров и вызывать диалоги NCP. Есть примечание, методы onTalk и onKill будут вызывать только диалоги с NCP в зависимости от текущего состояния квеста. Метод onKill будет вызываться только тогда, когда мы убиваем квестового монстра.
# {) }1 n2 D4 x6 B: G$ h# B6 M# h- m3 M5 J8 e. O
; \4 c2 e8 [3 t
Давайте рассмотрим как вызывается метод onKill при убийстве keltir в состоянии квеста STARTED:
, ?* Q7 a$ w( @+ X# u* w1 j& s
  1. STARTED.addKillId(KELTIR_NPC_ID)
Скопировать код
и метод onKill в классе Quest:' A$ M  f7 U. g  V$ h& H) W" m
: X# |4 C0 K# o9 G, d3 U* V8 T
  1. class Quest (JQuest):
    ( @3 a, {  \& `, f/ g
  2.   ...; r& H1 v) W! w6 U' Y1 e3 w# w
  3.   def onKill (self,npcId,st):
    " S& }9 j% U: a& g( S# c
  4. if npcId == KELTIR_NPC_ID:
    " `; a) H, W* d
  5.    n = getCount(st)
    3 Y6 l# o/ C5 |) O% S
  6.    if   n == 0:
    0 y/ W# t  [, C5 H; U; B
  7.        return "Chat0.htm"
    ' I5 a/ `/ `+ h6 K/ f
  8.    elif n == 1:9 q! r2 o0 N" Q9 N/ b$ E
  9.        return "Chat1.htm"
    ' R: T/ \, v! H" G& F
  10.    elif n >= 4:. m4 u. U& d) L' f9 [, S
  11.        return "Chat4.htm"
    5 x, I' ?% U: a1 \$ Y
  12.    return "Collected "+str(n)+" of 4 fangs"
    " B  u1 {) c' |, d) ?
  13. return
Скопировать код
Метод onKill (а так же метод onTalk) имеет следующие параметры:4 @+ {6 O  L0 {$ l) F  K) g

1 D6 M  y3 v3 W$ U3 O- x  w! t/ o
/ f' G6 w& H" t) O
• self – квест
% ^8 @0 h9 g; f6 Z& J• npcId – ID NCP, которого мы должны убивать (если это метод onTalk, то ID того NCP, с которым мы должны поговорить)./ @# K7 {) k+ u3 }4 S2 u
• st – текущее состояние игрока.1 D/ W4 J( p' `6 [
9 ]" W! G4 f: n5 V. G

- z2 ^6 Z. e& I2 ^В этом методе мы проверяем и отмечаем, является ли убитый NCP keltir’ом. В основном эта проверка не нужна, т.к. у нас только KELTIR_NPC_ID.
* ~' k: ]) S% K3 \1 H, w/ f
3 Z  K# l3 a& |3 ?% X1 N8 B$ K

, x+ L/ h+ T" S1 v. VЗатем проверяем количество предметов (в данном случае количество клыков), и если их вообще нет, то возвращаем строку "Chat0.htm", если только один предмет, то возвращаем строку "Chat1.htm", если же предметов 4 или больше, то "Chat4.htm". Если строка возвращена из методов onEvent, onKill или onTalk, то сервер покажет соответствующие htm. В Chat0.htm может иметь следующий текст: «Вы не имеете ни одного клыка, возвращайтесь позже, когда соберете 4 штуки и бла, бла, бла…», в Chat1.htm может быть следующий текст: «У Вас всего 1 клык, по этому соберите еще…». В Chat4.htm – «Вы собрали необходимое количество предметов, возвращайтесь к вашему тренеру, что бы завершить квест…»' e* Y& \9 ^  I5 u, p1 W1 R

: Q" j3 R7 j1 S' ?
0 K4 j: ^3 z1 O7 x$ R4 J
Примечание: если в строка return начинается с "<html>", то будет показана страничка html с текстом, который стоит далее. Так вместо:+ w. Y9 |- r$ ?5 |
return "Chat4.htm"% j3 i5 q8 O) |7 `2 a- E; |( y2 b: ~
3 g! D9 \. B4 e% ^

7 f6 r( m0 h& G% Fможно поставить:
0 M: \) d5 L1 [! r5 m$ Y( B
  1. return "<html><body>Return to your trainer to complete the quest</body></html>"
Скопировать код
Так же если строка заканчивается без .htm или в начале нет <html>, то текст будет выведен, как системное сообщение в окне чата. В нашем случае мы сделаем так, что бы при каждом убийстве keltik выводилось системное сообщение: «Собрано N из 4-х клыков».
3 c1 j( h' @2 e4 c2 z6 k* t
  u$ @1 E& i1 d/ G. A
* K# W9 \6 L0 p+ l
Наш код для onKill имеет один недостаток. Он будет постоянно показывать Chat0.htm, Chat1.htm и Chat4.htm, нам же необходимо, что бы Chat0.htm и Chat1.htm показывались только один раз. Как нам это сделать? С помощью переменных.& F7 R& J5 ?8 u9 w$ {
7 V. K$ V) U+ r$ n( ~, t! }
2 c$ l( Y) i! R& Z
В каждом квесте строки могут храниться с помощью переменных. Эти переменные сохраняются в Вашей БД. В каждом методе мы можем назначить, прочитать и удалить переменные. Давайте изменим метод onKill, так что бы каждый диалог вызывался только один раз.
0 X/ }- T/ L  H  w5 w+ [$ W6 T
  1. def onKill (self,npcId,st):
    ) [6 h& o8 P" P, E/ G) L$ @! d
  2. if npcId == KELTIR_NPC_ID:
    5 Y; Q) s8 |+ C
  3. n = getCount(st)
    8 j- [9 T: Z7 R" N
  4. if n == 0:
    3 ~4 y$ ?* H: A9 i8 Z, `; B& v
  5. if st.get('chat0') == None :
    + l$ B6 {' @3 e; x- F1 P
  6. st.set("chat0", "true")/ V) Q8 D. @8 ]8 S7 M
  7. return "Chat0.htm"9 L) a8 C0 a9 [9 Z! y
  8. elif n == 1:
    # h- ^" {5 h% i
  9. if st.get('chat1') == None :/ K9 C& D$ M" {4 ]& |1 L& G. w) J0 |3 N
  10. st.set("chat1", "true")6 ~% b) P  c" j+ o" _& S' X; h* o" C
  11. return "Chat1.htm") Z* T& u* J- g" B  G
  12. elif n >= 4:* K6 m" f: X7 w* h8 m7 ~4 r
  13. return "Chat4.htm"
    0 D0 c  f# G+ x" \% @
  14. return "Collected "+str(n)+" of 4 fangs"" P' q, N: v$ L" ?0 z/ 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.) K6 B) R# g  }' k
' T6 B  a. d) ?6 T+ P+ r7 \

( G( ]2 z  l; v  F3 _Вот конечный рабочий вариант квеста:
& _5 g% N4 Z' E: [/ h/ I
  1. import sys
    1 X& e) N) l4 H: R$ r6 n
  2. from net.sf.l2j.gameserver.model.quest import State
    $ y9 H" `# g. X1 Y' ], C3 D& y
  3. from net.sf.l2j.gameserver.model.quest import QuestState% B8 s7 |6 y$ v0 z: P
  4. from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest
    7 I, H. h2 @% E+ {; @
  5. : F/ r4 l! C, C: S8 c+ V
  6. KELTIR_NPC_ID = 12082' i5 j3 R9 h  W) Y0 w1 k& x5 s
  7. FANGS_ITEM_ID = 1859" X) o+ I7 n8 [* {; A
  8. DROP_RATE    = 500000
    ' Z( |5 U, L5 L* b% c0 s4 v9 t

  9. $ ^5 o+ S/ \2 {# L3 ~  V
  10. WORLD_MAP_ITEM_ID = 1665
    2 d6 A  L& z, v) ]- j" y# V

  11. 9 A3 g/ C) Y% y3 J2 {- n4 [
  12. def getCount(st) :
    - n  n3 B- a% P, I& i
  13. return st.getQuestItemsCount(FANGS_ITEM_ID)
    9 t! q+ K3 c+ {- ], P6 W
  14. ( Y# ~9 ]9 S: W: [" R
  15. def completed(st) :4 [% |- A, k/ e' C1 _$ g) l; [
  16. st.setState(COMPLETED); G4 B% T7 h& h1 @/ @
  17. st.clearQuestDrops()6 ?$ Q" u7 w0 T% j+ k
  18. st.takeItems(FANGS_ITEM_ID,-1)
    # H! k2 M) R" ]2 ~! G
  19. st.giveItems(WORLD_MAP_ITEM_ID,1)
    8 J6 P8 p% i- p; {
  20. st.exitQuest(False)( o& K$ m  c. S  J
  21. return
    % h9 `. D0 A) U  \& t: K
  22. 1 w' u/ `, P) ^
  23. def check(st) :
    0 e4 A7 N' Z" Y) w
  24. if getCount(st) >= 4 :
    8 H& s+ m. u- F6 @7 |' O8 |
  25. completed(st)2 r9 ~% N; F/ J7 V7 ?% L: g
  26. return
    + A# D6 ^& G/ h/ N+ c6 s

  27. ; s" q9 L5 q$ F& Y' o. \
  28. class Quest (JQuest):' f$ s% g6 x7 T4 S' O
  29. 9 S/ C3 Q$ |5 t# r% Y4 _+ a, J
  30. def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)
    ( }& v& R, L. R- S+ T1 [8 J/ _
  31. " {4 `  b, h% R  z. O- [% w- P2 e8 P
  32. def onEvent (self,event,st):' F& l" t9 f$ _! i( y5 h
  33. id = st.getState()
    2 i; d4 t5 l% k7 G  a
  34. if id == CREATED : st.setState(STARTED)3 U# D2 A/ {; K$ A% w9 I1 `
  35. elif id == COMPLETED: pass  C+ r% b9 Y( `7 G; C9 {/ g
  36. elif id == STARTED : check(st)
    * m) B6 U4 Q0 z- V) M0 q
  37. return
    8 a0 t: d9 T. {) D  d8 B

  38. ' T6 A' ]; b$ H
  39. def onKill (self,npcId,st):
    * {( c% f" W0 j4 \
  40. if npcId == KELTIR_NPC_ID:
    9 D" n& H0 j/ ?' V8 ]
  41. n = getCount(st)
    & v7 ~, T0 U; R( Y- U$ T
  42. if n == 0:- H: O: U/ d. S' F! L0 x* |9 u8 D
  43. if st.get('chat0') == None :
    % [0 {- C! X" a2 P: I
  44. st.set("chat0", "true")
    0 |! x9 e3 l* d/ Z0 K8 H5 G" D
  45. return "Chat0.htm"
    ! r2 D3 g2 o+ t& u- P
  46. elif n == 1:
    4 e& T: d) ~5 ]2 z6 I3 q; @
  47. if st.get('chat1') == None :
    7 X$ u% S7 A0 S' C
  48. st.set("chat1", "true")
      k$ O3 `. [; L8 y( _( w% {
  49. return "Chat1.htm"" q) N( O# z# }, j2 T% k
  50. elif n >= 4:
    % [$ i' t8 M" `- L
  51. return "Chat4.htm"
    0 e% A& B* u" U8 I, t1 h
  52. return "Collect "+str(n)+" of 4 fangs") E# w" V" W  u6 [, i0 L: ^9 {4 O
  53. return
    6 p3 f8 C( U9 l) `, y
  54. 8 r; ^) F) ]( i/ M
  55. QUEST    = Quest(201, "Tutorial", "Tutorial quest"). J! U, e" _& N; {' H
  56. CREATED = State('Start',    QUEST)
    & N$ v! H7 g9 G" i! Q
  57. STARTED = State('Started', QUEST)
      ~0 B7 [8 O: j+ J
  58. COMPLETED = State('Completed', QUEST)
    6 A* p: X* Y6 n' e
  59. # M2 b# e1 w& i' t' B2 D7 d
  60. QUEST.setInitialState(CREATED). g/ T& O- g1 @  g+ l
  61. QUEST.addStartNpc(7056)
    9 L) I7 j1 @; U! R( l0 z! j+ Z
  62. QUEST.addStartNpc(7012)8 p) q  B% m3 A) x2 d+ S
  63. QUEST.addStartNpc(7009)2 I& {; X- n( a: W- L( E
  64. QUEST.addStartNpc(7011)
    / ?2 [7 f: {: L' q' A+ n% q& x

  65. 9 Z7 v2 M. e. U- s
  66. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
    , y' R* x5 u. S& a& X! ~% z
  67. STARTED.addKillId(KELTIR_NPC_ID), u4 I8 m+ {. j' o- x
  68. STARTED.addTalkId(7056)
    & D. Y; o0 D# ^
  69. STARTED.addTalkI d(7012)
    , m3 t  B4 I4 J9 ^& g2 B" m/ w, e3 X2 O
  70. STARTED.addTalkId(7009)
    2 @  R" I  }: i6 ]: z8 R- B
  71. STARTED.addTalkId(7011)
Скопировать код
7 M2 {7 G2 l9 c2 _5 G( I3 p( T

* q' C: s& @$ B/ S, E' i




Добро пожаловать artace.ru - творческий сектор (https://artace.ru/) Powered by Discuz! X3.5