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

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

Автор: admin    Время: 2024-9-17 19:36
Название: Создаём собственные квесты (часть 2)
Хроники        Interlude' L( `+ B3 U' W7 W) L9 {
Сборка        L2j
0 M3 Q5 w/ x9 m9 N1 y/ H+ hОбратите внимание: в файле htm стартового NCP обязательно должна быть ссылка на квест:
6 b0 z' f" n1 {  O. `$ g( {# G
  1. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста:
) G( t2 N) G) Q  h& x0 Z: b5 U. X; S: ?6 A2 f
  1. if getCount(st) >= 4 :
    - r) C/ a: u* U: B& n
  2. completed(st)
    2 g/ e. R: o/ I) {4 k* x8 j
  3.   return) [) R! f( W; M4 I6 p" d- E, s

  4. ( j( k. s$ \+ |* M9 F( j
  5. class Quest (JQuest):
    ) V+ h# p: b: ]3 ^0 j% t& ]+ K
  6.   def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)" w$ r9 j, p, t; z" l1 N
  7.   def onEvent (self,event,st):' {, A9 y2 Q3 h* t0 f( k9 l
  8. id = st.getState()
    2 ]- E6 X: u2 q: T4 K  }
  9. if   id == CREATED  : st.setState(STARTED)5 D+ _6 f, u! `7 [: K% q
  10. elif id == COMPLETED: pass
    . G5 r. \5 H; {3 g- d
  11. elif id == STARTED  : check(st): r! D6 f. A( F
  12. return, X& ]8 K5 d8 _4 q; Q$ ?$ D2 y4 O
  13. 5 z" a; o+ [6 z. ~
  14. QUEST     = Quest(201,"Tutorial", "Tutorial quest")
    " B$ _3 [0 z0 Z+ z- n
  15. CREATED   = State('Start',     QUEST)! K8 S7 S/ Z# R: S4 d
  16. STARTED   = State('Started',   QUEST)" I; w) B/ a' J8 w, S: R
  17. COMPLETED = State('Completed', QUEST)+ S2 \9 C$ M9 V: {4 y
  18. # |6 }4 u3 d$ b
  19. QUEST.setInitialState(CREATED)* l$ i3 e! ]* ^: M1 j
  20. QUEST.addStartNpc(7056)8 }7 `) {3 |4 m. o" M3 c. H( b. Z
  21. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Теперь рассмотрим, как это работает.) N% H' k9 ?- l* {0 C
Игрок подходит к начальному NCP (в данном случае 7056), нажимает на «Quest». Квест будет создан и состояние квеста перейдет к CREATED и игроку будет показана страничка Start.htm с описанием квеста. Тогда метод onEvent, поле открытия странички Start.htm переведет состояние квеста в STARTED и игроку будет показана страничка Started.htm, где будет опсание того, как найти keltirs и .т.д.
: V) P3 }# v3 K, G, o7 ]- ~0 p4 `0 G* Q" n- a7 z3 {5 w
8 w* E* G/ K# l" h$ n# I/ C
При состоянии STARTED будет зарегистрирован дроп «fangs» при убийстве keltirs. Игрок может вернуться к стартовому NCP и спросить о квесте – метод onEvent будет вызван снова. Если у игрока не хватает необходимого количества предметов, то метод check() не переведет квест в следующее состояние и Started.htm будет показана снова. Но если игрок собрал необходимее количество предметов (в данном случае 4 клыка), то метод check() вызовет метод completed() который переведет квест в новое состояние COMPLETED, заберет все клыки, даст карту мира, т.к. это награда за квест, покажет Completed.htm и завершит квест.
1 @0 g( }$ d8 c' i! d4 Y% Z' X6 c4 |) j% C% _

. o6 u9 U, n: l, A# |Теперь давайте сделаем наш квест более похожим на то, что он должен из себя представлять.% K" s! \+ m( l3 {5 J3 h, @
Прежде всего у нас есть 3 метода для объявления их в Яве – onTalk, onKill и onEvent. Если методы onTalk и onKill не объявлены, то за них все будет делать метод onEvent, т.е. определять квестовых монстров и вызывать диалоги NCP. Есть примечание, методы onTalk и onKill будут вызывать только диалоги с NCP в зависимости от текущего состояния квеста. Метод onKill будет вызываться только тогда, когда мы убиваем квестового монстра.
# ]  R8 q  \) L
1 I5 r* {- c. K4 r/ S9 l1 |8 |

' e) u8 }1 {# b5 z. `' U  @2 y7 uДавайте рассмотрим как вызывается метод onKill при убийстве keltir в состоянии квеста STARTED:
9 m; D6 f2 L) f+ ?1 ]0 U. y
  1. STARTED.addKillId(KELTIR_NPC_ID)
Скопировать код
и метод onKill в классе Quest:
/ [9 h" c$ c6 v! F
; I) p6 N! Z+ a) a( E
  1. class Quest (JQuest):
    % d/ U" @; t& E. k0 g6 q$ n1 A1 A3 B
  2.   ...
    5 \7 c& `, |( W* Y0 @: G4 ^
  3.   def onKill (self,npcId,st):
    ) l8 V- o" G: S* v# s5 F
  4. if npcId == KELTIR_NPC_ID:/ n, `1 {+ N- J  m/ K" \
  5.    n = getCount(st)
    $ {' R" c4 \( \8 l% N+ q  }
  6.    if   n == 0:
    / m$ r/ R! u1 T9 r! j0 W& S
  7.        return "Chat0.htm") J& Z6 D. Y' ~
  8.    elif n == 1:) o. L0 H9 I  M1 X. t7 V
  9.        return "Chat1.htm"  e7 h1 ?& }5 U' j1 F
  10.    elif n >= 4:
    , O, g4 j3 g7 {$ [2 J& o0 M4 |5 e+ \
  11.        return "Chat4.htm"" ?* c3 i6 G" V; t
  12.    return "Collected "+str(n)+" of 4 fangs"
    3 H% m1 I5 p1 R  {8 D- i. J
  13. return
Скопировать код
Метод onKill (а так же метод onTalk) имеет следующие параметры:2 j5 ^" N2 D- o( D

+ h- i' j) b- g" _2 o  l4 {$ p) R
* W$ a. A9 v& \. e3 g6 g
• self – квест: v: V) i: N# K8 R
• npcId – ID NCP, которого мы должны убивать (если это метод onTalk, то ID того NCP, с которым мы должны поговорить).2 v& M5 S" i1 R9 Y3 @1 M% Z: C$ X
• st – текущее состояние игрока.7 }* Z6 `5 m# r, G! k
% e1 v' J' i$ U6 R
9 G4 r4 ?8 @+ j$ M) l. ~
В этом методе мы проверяем и отмечаем, является ли убитый NCP keltir’ом. В основном эта проверка не нужна, т.к. у нас только KELTIR_NPC_ID.
6 V2 A3 B! b. G  a6 Q$ ~7 A
* W8 v; B- R& I& L& P4 h! z" ?; D
$ O6 |/ c3 }: s
Затем проверяем количество предметов (в данном случае количество клыков), и если их вообще нет, то возвращаем строку "Chat0.htm", если только один предмет, то возвращаем строку "Chat1.htm", если же предметов 4 или больше, то "Chat4.htm". Если строка возвращена из методов onEvent, onKill или onTalk, то сервер покажет соответствующие htm. В Chat0.htm может иметь следующий текст: «Вы не имеете ни одного клыка, возвращайтесь позже, когда соберете 4 штуки и бла, бла, бла…», в Chat1.htm может быть следующий текст: «У Вас всего 1 клык, по этому соберите еще…». В Chat4.htm – «Вы собрали необходимое количество предметов, возвращайтесь к вашему тренеру, что бы завершить квест…»
$ C0 x; E! |% {$ L0 T3 u6 e
# c( L7 b& x, X, X6 R: N

# N$ v. n6 n. a8 S# Y+ k1 [" `$ C. x2 ]Примечание: если в строка return начинается с "<html>", то будет показана страничка html с текстом, который стоит далее. Так вместо:* G0 T6 P% j+ ?8 q0 K
return "Chat4.htm"
5 i* P, W4 x, O- Q2 w& \* @* N, V- q

+ o9 w1 O+ e0 R+ u) I9 zможно поставить:
  [7 |! Q; q  p% y
  1. return "<html><body>Return to your trainer to complete the quest</body></html>"
Скопировать код
Так же если строка заканчивается без .htm или в начале нет <html>, то текст будет выведен, как системное сообщение в окне чата. В нашем случае мы сделаем так, что бы при каждом убийстве keltik выводилось системное сообщение: «Собрано N из 4-х клыков».
" H& j: M( ?7 x# g
: A; c& Z# U: H0 c# m: J
3 T* H; M5 Q/ }& Q
Наш код для onKill имеет один недостаток. Он будет постоянно показывать Chat0.htm, Chat1.htm и Chat4.htm, нам же необходимо, что бы Chat0.htm и Chat1.htm показывались только один раз. Как нам это сделать? С помощью переменных.
5 F: h/ L8 z: k0 C- ^1 s8 p
- Y/ G: ]( [8 g& e& O

; `7 r- s0 X& Q) MВ каждом квесте строки могут храниться с помощью переменных. Эти переменные сохраняются в Вашей БД. В каждом методе мы можем назначить, прочитать и удалить переменные. Давайте изменим метод onKill, так что бы каждый диалог вызывался только один раз.' o+ t" n3 X  t: z( T* E0 w
  1. def onKill (self,npcId,st):4 {& b- ~! m3 G, f0 n& C. k
  2. if npcId == KELTIR_NPC_ID:7 ^% s: E9 s$ z
  3. n = getCount(st)/ a3 }5 C2 u9 F; W% X, s
  4. if n == 0:
    ( _/ m8 A' I0 i% r9 e- `. c. c
  5. if st.get('chat0') == None :
    ) c  x4 t& S: V9 Y% W% i
  6. st.set("chat0", "true")
    6 z6 n1 x4 H" }$ S0 f  O
  7. return "Chat0.htm"% Q4 ^" ]& d, W5 }. i. k5 V
  8. elif n == 1:
    ( x- G" ^1 M3 [
  9. if st.get('chat1') == None :
    1 U" b+ m: Q! h5 j( R3 J4 A
  10. st.set("chat1", "true")6 X# U5 r7 p' d; x2 ~5 H
  11. return "Chat1.htm"
    $ B% E+ K6 M; T- Z: f
  12. elif n >= 4:( k3 g! Z8 V& k% y: i& p
  13. return "Chat4.htm"- h+ p+ j! T7 i% ]2 i8 m- f
  14. return "Collected "+str(n)+" of 4 fangs", l! i. |% `9 W. t
  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.
7 ^) }: i: \6 X; V0 Y* w% h
$ S: ^7 z8 }( `2 O- T+ _$ k

. N- u3 [2 d( k' `3 {: lВот конечный рабочий вариант квеста:* {5 O$ ~' y3 T* C% B, l; {4 [
  1. import sys
    ( I. l8 M! R5 Y7 b2 t+ Q' r1 {0 g- E
  2. from net.sf.l2j.gameserver.model.quest import State
    , e: Y5 l, c; d2 H
  3. from net.sf.l2j.gameserver.model.quest import QuestState
    ! Q) g# ~; Z7 y' `5 s3 [: A
  4. from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest
    ( ~( e1 x% V" M7 e
  5. 3 y* p# G2 `& e& m
  6. KELTIR_NPC_ID = 12082+ b, m9 v5 p# g0 w8 ?3 K* R
  7. FANGS_ITEM_ID = 1859, H# Q/ q, R3 q
  8. DROP_RATE    = 500000
    3 w* I6 c9 l/ c9 W2 {' g9 Z
  9. : w' O3 B# l) u- J" B1 A
  10. WORLD_MAP_ITEM_ID = 1665! r6 u0 r" G8 t

  11.   H7 J0 P9 u! n! \/ D& L: U  u
  12. def getCount(st) :
    $ }# \, z' T" @4 S! h! D
  13. return st.getQuestItemsCount(FANGS_ITEM_ID)* y( s9 |" a6 }
  14. 6 Y7 }! U" c: e
  15. def completed(st) :
    - h) q& S; Q% b
  16. st.setState(COMPLETED)3 M! a$ ]/ W4 y1 i- e( m( v5 M
  17. st.clearQuestDrops()5 V  |9 b& E; {4 ]
  18. st.takeItems(FANGS_ITEM_ID,-1)
    & t# T0 S  j* t" X
  19. st.giveItems(WORLD_MAP_ITEM_ID,1)" }! F* B5 `1 n1 L0 W; S
  20. st.exitQuest(False)
    1 B( N: C5 G2 h# T# ?
  21. return
    / x' v3 I( B9 C- I) s; k7 P
  22. * f0 ?0 w, k( M+ U, t+ ^
  23. def check(st) :
    9 |- d+ Z0 J3 n: x; n  l
  24. if getCount(st) >= 4 :8 Q  x; M; d5 d' V& J) c: ~6 t
  25. completed(st)  I$ `5 }' G% y/ F$ @
  26. return! _1 k5 I: N; ?  M

  27. 4 X. o6 X/ z+ Y+ g
  28. class Quest (JQuest):. O, |* ]2 F+ G

  29.   {# k  G' v( z5 [% U
  30. def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)
    6 F7 @& D0 b4 @- H* @

  31. 0 w5 C0 j* l. z
  32. def onEvent (self,event,st):: F: G2 ?0 L( _" |* {( f2 N
  33. id = st.getState(). T: W9 b5 J. _& B/ G& D8 |5 v  t
  34. if id == CREATED : st.setState(STARTED)% n) T8 V9 R! k( h
  35. elif id == COMPLETED: pass- y' X2 G. I, V
  36. elif id == STARTED : check(st)- X: a+ m+ t  ]) q  b/ s4 V0 w9 W
  37. return
      s# U" `6 h7 N8 ]: \3 o$ Y  y

  38. ' Q6 r2 d% v6 M0 j
  39. def onKill (self,npcId,st):
    $ D% _; V; F  X* A2 G0 A
  40. if npcId == KELTIR_NPC_ID:) m+ ~% w, w; Q( |$ H2 W) I
  41. n = getCount(st)# f! v. y, H/ X3 n
  42. if n == 0:
    % H. x4 ]4 a3 z9 s4 V" g6 W
  43. if st.get('chat0') == None :2 A$ p+ A- V; z8 K
  44. st.set("chat0", "true")9 E7 H, j1 k! k- k/ P9 z
  45. return "Chat0.htm"- U# o( b* N5 _' v8 ?# q/ V% o
  46. elif n == 1:, Q' s: [* w6 u8 K
  47. if st.get('chat1') == None :
    - U+ E' R7 {- F1 ]/ N6 D2 L
  48. st.set("chat1", "true")% G, J8 ^7 U1 h3 v2 o/ @3 a3 x
  49. return "Chat1.htm". D% q! d. E' m9 Y+ K1 \5 g/ o
  50. elif n >= 4:! _/ _* U& f3 L6 a! ~
  51. return "Chat4.htm"( y- {) l! F! `! i
  52. return "Collect "+str(n)+" of 4 fangs"
    , i+ V0 n' ?, ]# s2 ~3 K" K3 D. u
  53. return
      |2 u! [4 v) ~0 `3 l. w4 J- N. b
  54. $ K$ s' j3 N8 o- `: a4 U2 L& S3 `
  55. QUEST    = Quest(201, "Tutorial", "Tutorial quest")3 G) u5 A1 I1 x$ f: H# r  K
  56. CREATED = State('Start',    QUEST)9 N% q( I3 ~# ~' Y+ t' n- T
  57. STARTED = State('Started', QUEST)  f$ m% [* w& q, Z, L# c
  58. COMPLETED = State('Completed', QUEST)% P& J8 c) [* c; \8 m* h! w

  59. ) S7 P, X' G6 ?/ z  U
  60. QUEST.setInitialState(CREATED)4 B/ ^! w" z: i( V4 L
  61. QUEST.addStartNpc(7056)
    ! P* Z& v$ G5 C7 v; F* I
  62. QUEST.addStartNpc(7012)2 Z0 I- O) U  f! [& @
  63. QUEST.addStartNpc(7009)2 T' l$ h" w/ X; @/ T; W
  64. QUEST.addStartNpc(7011)
      t% f# w6 I5 f6 f' \  s- Q! ^

  65. 9 T' u+ p4 ^3 y! I
  66. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)! @" H6 |9 Y$ f* e. ^9 |9 o; d
  67. STARTED.addKillId(KELTIR_NPC_ID)" p$ Y, }9 h7 B0 w3 ~
  68. STARTED.addTalkId(7056)1 z  a# T) u/ u  A; L) V$ F3 ]
  69. STARTED.addTalkI d(7012): ?3 L2 a8 o4 w0 n4 o* E! w
  70. STARTED.addTalkId(7009)
    0 ]$ i" ^8 g' G
  71. STARTED.addTalkId(7011)
Скопировать код

/ Y" z# N! i* s0 U5 W( m  H) j8 a2 _) N7 @, W9 o





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