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

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

Автор: admin    Время: 2024-9-17 19:36
Название: Создаём собственные квесты (часть 2)
Хроники        Interlude8 B2 Z8 J. A: z; t( [- D
Сборка        L2j/ i+ ~# h0 r8 p+ _
Обратите внимание: в файле htm стартового NCP обязательно должна быть ссылка на квест:
5 t5 b5 A2 p( ]& q  n7 k! N
  1. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста:' a/ E: d- {0 A3 q) x( Z& E

5 ~+ ~4 A: [; O! f, g/ h1 L
  1. if getCount(st) >= 4 :5 o3 r. K9 H' L# Z+ q, H5 q1 q
  2. completed(st)
    ( K8 t; i/ d6 ]
  3.   return& \; O( s" h+ q# c8 H+ c# |
  4. " H( Q" K+ Z; l3 y+ u: J
  5. class Quest (JQuest):& g( B3 w. N& K* p; q
  6.   def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)5 N& [+ m% @$ V: R9 y" q
  7.   def onEvent (self,event,st):
      j4 q! u9 j7 N! W* d9 k1 Z' W$ R
  8. id = st.getState()3 d6 ^8 @" ]% Q) o; s  p
  9. if   id == CREATED  : st.setState(STARTED)4 z1 |+ V' W9 y. `) R
  10. elif id == COMPLETED: pass
    . J  H% c" `2 J' ?8 K; k5 v8 L4 U6 ~
  11. elif id == STARTED  : check(st)
    * D  y6 W" y* c2 R1 s% l
  12. return4 \* k6 t% w' h! y' |# ]( k

  13. ! s2 Z  C9 Y# Q9 ]$ {6 n  \
  14. QUEST     = Quest(201,"Tutorial", "Tutorial quest")1 V8 H! ?1 l. I' s% `8 J
  15. CREATED   = State('Start',     QUEST)
    7 o; w) G2 K1 X
  16. STARTED   = State('Started',   QUEST)
    ; m2 E0 B0 O- e6 z  J) {1 ?
  17. COMPLETED = State('Completed', QUEST)
    : \  t; g' z) d: X" U1 l$ ~

  18. 8 `$ g2 c3 ?$ W/ f+ |6 e" \3 ]. \
  19. QUEST.setInitialState(CREATED)
    * {; T6 ^( u, O3 G' v* I" V! T
  20. QUEST.addStartNpc(7056)
    " g! }- x3 a& {8 A4 C2 N# R/ U$ k
  21. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Теперь рассмотрим, как это работает.+ k0 l3 q  U: ~2 `
Игрок подходит к начальному NCP (в данном случае 7056), нажимает на «Quest». Квест будет создан и состояние квеста перейдет к CREATED и игроку будет показана страничка Start.htm с описанием квеста. Тогда метод onEvent, поле открытия странички Start.htm переведет состояние квеста в STARTED и игроку будет показана страничка Started.htm, где будет опсание того, как найти keltirs и .т.д.; o7 G3 B9 ?; w

0 m8 I/ n8 W9 i- {6 S5 ~/ t+ u
$ W, D8 R& P6 b; q0 M4 H
При состоянии STARTED будет зарегистрирован дроп «fangs» при убийстве keltirs. Игрок может вернуться к стартовому NCP и спросить о квесте – метод onEvent будет вызван снова. Если у игрока не хватает необходимого количества предметов, то метод check() не переведет квест в следующее состояние и Started.htm будет показана снова. Но если игрок собрал необходимее количество предметов (в данном случае 4 клыка), то метод check() вызовет метод completed() который переведет квест в новое состояние COMPLETED, заберет все клыки, даст карту мира, т.к. это награда за квест, покажет Completed.htm и завершит квест.
1 U9 o- B. H+ G% X3 y' A/ _9 ^
* m/ P" O. \6 E8 Y( c; G
1 f/ R1 _4 W. p$ |' o7 a
Теперь давайте сделаем наш квест более похожим на то, что он должен из себя представлять.
, z/ O- m$ k4 p, Y" `* DПрежде всего у нас есть 3 метода для объявления их в Яве – onTalk, onKill и onEvent. Если методы onTalk и onKill не объявлены, то за них все будет делать метод onEvent, т.е. определять квестовых монстров и вызывать диалоги NCP. Есть примечание, методы onTalk и onKill будут вызывать только диалоги с NCP в зависимости от текущего состояния квеста. Метод onKill будет вызываться только тогда, когда мы убиваем квестового монстра./ ~1 w: L  X+ w3 _; m# F
, k. U2 D$ V5 q  F# v) Y, B9 k
. m: `5 |! s) i% f! @$ Z' U
Давайте рассмотрим как вызывается метод onKill при убийстве keltir в состоянии квеста STARTED:3 U2 E& L7 a! k+ U& {. u
  1. STARTED.addKillId(KELTIR_NPC_ID)
Скопировать код
и метод onKill в классе Quest:
* \* D6 {2 N5 M3 N: q0 N1 Y. \8 T4 ?, `
  1. class Quest (JQuest):
    ; j% T% x6 g7 e5 n$ B$ h5 X8 W4 b( n
  2.   ...  t) A- K% W  o) U6 N
  3.   def onKill (self,npcId,st):
    8 c7 t1 d' X; s8 T. `5 k8 [6 r
  4. if npcId == KELTIR_NPC_ID:
    ' o/ f3 J" K1 ?7 O( U& o% K
  5.    n = getCount(st)4 D! i, G% }$ ^0 U  t% X3 h, X# ^
  6.    if   n == 0:2 D8 u7 q$ A9 n4 L$ y
  7.        return "Chat0.htm") e  k$ R- U7 d* I. m( C6 |
  8.    elif n == 1:# n5 m1 c& n) L7 {
  9.        return "Chat1.htm"
    ! r* {4 |! o' x7 X
  10.    elif n >= 4:
    , X* b! s, ]& Z  N. [8 [. p
  11.        return "Chat4.htm"- K1 S2 v9 k5 Q8 f" O, B
  12.    return "Collected "+str(n)+" of 4 fangs") b' ]4 K2 z7 p
  13. return
Скопировать код
Метод onKill (а так же метод onTalk) имеет следующие параметры:8 p* E  Q; G$ y: D! M1 E( l: E
: Y1 @, Z3 r, r1 n
" d; P$ [, g- O& _$ y1 \; r7 I: S( A
• self – квест% p) l1 z7 R: C  B
• npcId – ID NCP, которого мы должны убивать (если это метод onTalk, то ID того NCP, с которым мы должны поговорить)." I# d; \) v! T4 W$ `9 H# O
• st – текущее состояние игрока.+ r2 C% B% `  N/ h4 ^8 g

- K3 M: }/ ~5 W4 B# B
5 b, L7 |; `) o5 D: z: l
В этом методе мы проверяем и отмечаем, является ли убитый NCP keltir’ом. В основном эта проверка не нужна, т.к. у нас только KELTIR_NPC_ID.
5 Z; U6 b" Q% D# H# H  [) a2 \7 j4 Y
$ U' M. ^8 j: N: e6 P0 K
  @% g# x. Z; K0 b
Затем проверяем количество предметов (в данном случае количество клыков), и если их вообще нет, то возвращаем строку "Chat0.htm", если только один предмет, то возвращаем строку "Chat1.htm", если же предметов 4 или больше, то "Chat4.htm". Если строка возвращена из методов onEvent, onKill или onTalk, то сервер покажет соответствующие htm. В Chat0.htm может иметь следующий текст: «Вы не имеете ни одного клыка, возвращайтесь позже, когда соберете 4 штуки и бла, бла, бла…», в Chat1.htm может быть следующий текст: «У Вас всего 1 клык, по этому соберите еще…». В Chat4.htm – «Вы собрали необходимое количество предметов, возвращайтесь к вашему тренеру, что бы завершить квест…»! y8 m5 ?& \3 B8 H
3 K2 p2 c3 p# l, a8 Z3 h
: D  L! }2 P" i* Y! ~
Примечание: если в строка return начинается с "<html>", то будет показана страничка html с текстом, который стоит далее. Так вместо:
% E2 U" G/ j1 l$ ~( R1 l. Z: H' z, Mreturn "Chat4.htm"# ^8 i4 {9 c: f& I( ~+ c

, G4 l# o: G" `/ K; _
1 t* W8 w& v- W) \& U! Z
можно поставить:
7 A8 N) _: p9 e$ x4 Q1 s5 M6 ~9 J0 ]$ W
  1. return "<html><body>Return to your trainer to complete the quest</body></html>"
Скопировать код
Так же если строка заканчивается без .htm или в начале нет <html>, то текст будет выведен, как системное сообщение в окне чата. В нашем случае мы сделаем так, что бы при каждом убийстве keltik выводилось системное сообщение: «Собрано N из 4-х клыков»." u( z  q' [/ g$ X- Q: W# n* s
  D: n( S4 ~7 a
% _/ a& I% C7 B7 w7 z: x" g
Наш код для onKill имеет один недостаток. Он будет постоянно показывать Chat0.htm, Chat1.htm и Chat4.htm, нам же необходимо, что бы Chat0.htm и Chat1.htm показывались только один раз. Как нам это сделать? С помощью переменных.
- z! i& Y, _5 r; v7 }0 T) O; v1 V* V# {5 A) e
$ U/ V$ M' g) u/ S  v3 H' r% v
В каждом квесте строки могут храниться с помощью переменных. Эти переменные сохраняются в Вашей БД. В каждом методе мы можем назначить, прочитать и удалить переменные. Давайте изменим метод onKill, так что бы каждый диалог вызывался только один раз.7 x  e" u, k; W. C7 b
  1. def onKill (self,npcId,st):5 q. {/ F# m8 m8 J, V* U, l
  2. if npcId == KELTIR_NPC_ID:& L8 C' }+ O; h! T* z  m$ K9 J' i
  3. n = getCount(st)
    7 q) G+ k  X3 T" q5 i* Q; m
  4. if n == 0:' S8 S" d. c" f# \* [* D; y
  5. if st.get('chat0') == None :
    4 R8 Z3 Q, ^. M4 }5 I
  6. st.set("chat0", "true")
    & s- S" b% R2 O! E
  7. return "Chat0.htm") a& I! {4 _/ L
  8. elif n == 1:- f) U% E8 F; f2 ]$ B
  9. if st.get('chat1') == None :, Q0 m4 I' x6 u( T# Q  a  A; M
  10. st.set("chat1", "true")
    + R3 B& r+ B. G& }0 {
  11. return "Chat1.htm") ^' T& S* X  K
  12. elif n >= 4:4 o1 P& R! M7 L3 O0 B! H
  13. return "Chat4.htm", ?  H+ [+ s+ Y8 @3 K5 B* M
  14. return "Collected "+str(n)+" of 4 fangs"
    3 ^& d- e/ y* I6 z) S/ x8 t1 q
  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.
. {8 C: g- k" J- q/ ?" I  q% ?# P$ }+ s9 F
; c4 t+ `* X" ]7 b4 C- x
Вот конечный рабочий вариант квеста:7 g$ u: e1 F. z7 r* S# O; L0 {
  1. import sys1 I- p$ ^8 `) n1 \3 X
  2. from net.sf.l2j.gameserver.model.quest import State, |$ R! s2 e# f7 J/ i3 N6 W
  3. from net.sf.l2j.gameserver.model.quest import QuestState9 ^: D! l' n0 s4 r% ?
  4. from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest! k, x0 ^( v- D1 v- Z% I6 L

  5. & O+ S7 j# |1 \0 }* [( A: p' @
  6. KELTIR_NPC_ID = 12082
    3 h) v& ~" z1 D0 I% G
  7. FANGS_ITEM_ID = 1859
    ; R, e& [$ p) u! {  p3 \7 I5 K
  8. DROP_RATE    = 500000
    % i$ ~. r* u' l7 |

  9. 4 T: w2 P5 m/ _
  10. WORLD_MAP_ITEM_ID = 1665. L- A4 v" i( F& V, T- s; x- T
  11. 5 _! y6 p: [' }* k" K: p  a
  12. def getCount(st) :0 i6 ^3 @) B  c( K3 b/ t4 U9 _6 d8 ~
  13. return st.getQuestItemsCount(FANGS_ITEM_ID)1 B. y0 J5 u- t" m6 E
  14. # B0 v9 Q  X; u6 B$ L" v
  15. def completed(st) :
    / ?7 a6 G: T$ n
  16. st.setState(COMPLETED)0 f" y8 n/ z$ Z* F. ?% Y1 f
  17. st.clearQuestDrops()
    7 b0 h  w; q4 q% D- A3 z! n
  18. st.takeItems(FANGS_ITEM_ID,-1)' i$ p8 n- F9 v1 O+ u) U
  19. st.giveItems(WORLD_MAP_ITEM_ID,1)
    ( Z3 h5 T( J% Q
  20. st.exitQuest(False)
    7 D0 t2 @) g, M( u4 O. ?7 \
  21. return
    & ^, I; d' j  @; y" O! c
  22. ' j+ [/ [% d* B9 Z5 `' l7 W
  23. def check(st) :8 P: N' i! D, @" }9 Y
  24. if getCount(st) >= 4 :3 Z2 G, U5 H' ^3 g9 x# L8 F  H
  25. completed(st)) N. p( g  H' A" x
  26. return1 w! W1 k; P: q( U8 i5 P6 d

  27. ( \( K" c2 f: ?
  28. class Quest (JQuest):
    ( `1 m! u' v. U  x2 O7 |/ H5 V
  29. & m* z1 M/ P' @" t; Z1 |: @" {
  30. def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)/ J1 L, l3 a2 O+ b* a2 Y# Q

  31. 4 \+ g4 w( w7 K  d& h
  32. def onEvent (self,event,st):7 k. A% z0 o, }1 ~% ^2 J/ o' S
  33. id = st.getState()/ E$ t1 u% P3 k8 L8 E
  34. if id == CREATED : st.setState(STARTED)" C; }' u+ r7 W" v; n
  35. elif id == COMPLETED: pass) G! p) J7 D2 |; j
  36. elif id == STARTED : check(st)6 `# X1 _! K& Z6 B* N8 F
  37. return
    ( G- u1 @3 ^" _' T

  38. ' ^6 g* X) r" W, f' M9 K$ A
  39. def onKill (self,npcId,st):
      _8 B, }$ n& o" t
  40. if npcId == KELTIR_NPC_ID:
    # t! i! Q  x* r% o& T9 {
  41. n = getCount(st)
    , ?. [" @& p: L; W5 ]
  42. if n == 0:
    ) x0 K; d- b" B2 Y# L) q1 U
  43. if st.get('chat0') == None :( J5 j, e# W  X7 s0 l! ^
  44. st.set("chat0", "true")% u- |- }( x1 W* n" l# Y
  45. return "Chat0.htm"2 l3 z/ _% w1 f$ j. t% C, i0 L
  46. elif n == 1:
    7 q$ O9 X4 Q: \* O* F+ |( s
  47. if st.get('chat1') == None :
    3 C- e! [1 Y& C
  48. st.set("chat1", "true")
    4 z/ y% ?& o% c9 k
  49. return "Chat1.htm"
    - V6 G* K1 w) S) p& @' H+ z. V
  50. elif n >= 4:
    5 I  y- [$ G: h( M  w
  51. return "Chat4.htm"
    $ i8 N! [' ^# e7 ~% _. |) n9 U+ W
  52. return "Collect "+str(n)+" of 4 fangs". U  Q6 g! l4 F$ q( h2 B+ e( i
  53. return
    , \% [" V% _. X6 X$ U, m

  54. 9 p4 l0 o; g. Q9 q% d) n
  55. QUEST    = Quest(201, "Tutorial", "Tutorial quest")& F" D3 }3 `2 W7 q2 U
  56. CREATED = State('Start',    QUEST)
    7 z- u8 U" c+ {
  57. STARTED = State('Started', QUEST)
    5 J2 S7 [8 @. T# A
  58. COMPLETED = State('Completed', QUEST)
    , Q8 m* C$ Q3 J* ~' Q. K9 s. p6 ^% H
  59. ; x0 D! V& q% M2 u' a
  60. QUEST.setInitialState(CREATED)+ J) j1 Z$ j  N5 \
  61. QUEST.addStartNpc(7056)
    % A0 [5 H2 j* Y/ x# _
  62. QUEST.addStartNpc(7012)
    9 p$ z4 k6 r' T1 n* J, x
  63. QUEST.addStartNpc(7009)5 \6 a- ^' J. B$ b8 D8 e
  64. QUEST.addStartNpc(7011)- ~" U7 P) ?- g! G3 H0 n
  65. 8 z; V! Z" m( z0 h  ?: _' a
  66. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
    # c/ P4 x# ~$ i9 \5 s8 n4 K& }
  67. STARTED.addKillId(KELTIR_NPC_ID)/ t4 M- r# ^6 t
  68. STARTED.addTalkId(7056): c/ O; Q1 W! U; V: l
  69. STARTED.addTalkI d(7012)
    % y* }3 w' k- K: J( Y" u- X% f
  70. STARTED.addTalkId(7009)
    % }, G/ q' N6 ~
  71. STARTED.addTalkId(7011)
Скопировать код

* X, ]- C( M. h; `: W& e; |
6 g3 R8 f2 i8 {5 c' e0 ~" b




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