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

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

Автор: admin    Время: 2024-9-17 19:36
Название: Создаём собственные квесты (часть 2)
Хроники        Interlude
9 B$ e. L4 d& A, VСборка        L2j
2 c0 }" e! y  w; k. t! C- XОбратите внимание: в файле htm стартового NCP обязательно должна быть ссылка на квест:
& q  p) h% y1 z
  1. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста:
; W/ A' b- P- E6 `( u3 X& F) I
/ {- O% s9 D$ D- F9 ?# A
  1. if getCount(st) >= 4 :* N1 K' \( e: `
  2. completed(st)
    ' ~8 F, J/ c) Z# l
  3.   return( I( h1 j2 _# g2 c/ _

  4. : I# f" M' R& _& x
  5. class Quest (JQuest):% U2 N$ C; i+ \& ]) \& u$ x+ o
  6.   def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)* _3 a9 A) u" o* K+ S
  7.   def onEvent (self,event,st):
    0 d8 r5 F, W' i' w% _- G1 D
  8. id = st.getState()) h4 x& j$ ?/ ^9 J) U6 a; ^
  9. if   id == CREATED  : st.setState(STARTED)
    0 `5 \: p% O# g$ x
  10. elif id == COMPLETED: pass. I( Y/ i' N, h; ~" G4 \: V. l
  11. elif id == STARTED  : check(st)5 V/ B. ?: F, o: \7 q
  12. return% U, X5 W3 f2 T( S

  13. 1 |" m8 m2 k( y0 n1 k
  14. QUEST     = Quest(201,"Tutorial", "Tutorial quest")
    7 k. I5 D1 f8 O5 s& R% s
  15. CREATED   = State('Start',     QUEST)
    * d& y8 I) O3 G# R/ Z
  16. STARTED   = State('Started',   QUEST)
    . h8 ]5 y' @) x/ D9 p" `2 l1 z
  17. COMPLETED = State('Completed', QUEST)4 b- ^0 z0 [8 l# J* \0 O3 S
  18. # m7 w& G0 h! n- o% w; e& p5 t; _0 B
  19. QUEST.setInitialState(CREATED)! j& E( A1 v; m
  20. QUEST.addStartNpc(7056)
    " K* K! H6 D* w+ u$ u
  21. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Теперь рассмотрим, как это работает." b$ L3 O4 B- R) [3 z3 \
Игрок подходит к начальному NCP (в данном случае 7056), нажимает на «Quest». Квест будет создан и состояние квеста перейдет к CREATED и игроку будет показана страничка Start.htm с описанием квеста. Тогда метод onEvent, поле открытия странички Start.htm переведет состояние квеста в STARTED и игроку будет показана страничка Started.htm, где будет опсание того, как найти keltirs и .т.д.
5 ~) u2 C; t! C9 S- T+ e" \& o$ U/ l, |! z4 ?8 x9 S2 ^7 f
6 q( |0 D7 Y* I1 o# H
При состоянии STARTED будет зарегистрирован дроп «fangs» при убийстве keltirs. Игрок может вернуться к стартовому NCP и спросить о квесте – метод onEvent будет вызван снова. Если у игрока не хватает необходимого количества предметов, то метод check() не переведет квест в следующее состояние и Started.htm будет показана снова. Но если игрок собрал необходимее количество предметов (в данном случае 4 клыка), то метод check() вызовет метод completed() который переведет квест в новое состояние COMPLETED, заберет все клыки, даст карту мира, т.к. это награда за квест, покажет Completed.htm и завершит квест.
$ d2 R" r% K8 I. }: |1 m/ L* B
( D" B5 B+ t3 Q* g
! Y: H/ e! Q7 |
Теперь давайте сделаем наш квест более похожим на то, что он должен из себя представлять.2 |) s: R/ |* j1 c- g/ B
Прежде всего у нас есть 3 метода для объявления их в Яве – onTalk, onKill и onEvent. Если методы onTalk и onKill не объявлены, то за них все будет делать метод onEvent, т.е. определять квестовых монстров и вызывать диалоги NCP. Есть примечание, методы onTalk и onKill будут вызывать только диалоги с NCP в зависимости от текущего состояния квеста. Метод onKill будет вызываться только тогда, когда мы убиваем квестового монстра.2 M" n* E4 I/ v3 g

) J$ t* O4 A/ e

) T3 G5 ]. M( Y; d; K% H+ LДавайте рассмотрим как вызывается метод onKill при убийстве keltir в состоянии квеста STARTED:
8 a' h% E& {! l) b- S# a9 f
  1. STARTED.addKillId(KELTIR_NPC_ID)
Скопировать код
и метод onKill в классе Quest:) i- Y2 A+ \! V) ^
0 g* R" {# `* d5 U9 g/ L
  1. class Quest (JQuest):
    7 r: P. `$ N9 G- R2 U/ _) z
  2.   ...
    5 @6 e1 W0 O. r- N- E7 n
  3.   def onKill (self,npcId,st):
    ! d# F! \# p- O9 Q! m5 o/ J
  4. if npcId == KELTIR_NPC_ID:  ~. e' s* w/ y7 i3 a1 |
  5.    n = getCount(st)% i* j+ q6 V- R; ]; `
  6.    if   n == 0:
    ' r- t5 y8 H2 ~  g/ ?8 ]
  7.        return "Chat0.htm"
    4 s/ I6 p3 P4 Y+ A1 H
  8.    elif n == 1:2 u: Y' v3 }& l% O
  9.        return "Chat1.htm"+ |( `6 T, p% J8 o/ q6 j! Y# ?
  10.    elif n >= 4:$ E! J6 u( _3 W0 V. u  y
  11.        return "Chat4.htm"8 W( `; J. M7 X) E- G7 z
  12.    return "Collected "+str(n)+" of 4 fangs"
      L) y+ \" D0 T( R$ l
  13. return
Скопировать код
Метод onKill (а так же метод onTalk) имеет следующие параметры:
/ K2 R- q7 I% Q* o0 M" [& }  G0 h
! a5 s. v( f0 W: T7 g+ ?
• self – квест
( i* s) }# x6 B! {/ g; `6 L1 f6 n• npcId – ID NCP, которого мы должны убивать (если это метод onTalk, то ID того NCP, с которым мы должны поговорить).
- Q5 j/ E( o) a  |4 w* y• st – текущее состояние игрока.9 k6 x) K+ ~6 }$ x& b" q
, ?7 J* m7 A* q( x4 e& k: g
5 l! m3 |6 H+ C4 f) K$ f& b3 _
В этом методе мы проверяем и отмечаем, является ли убитый NCP keltir’ом. В основном эта проверка не нужна, т.к. у нас только KELTIR_NPC_ID.
& ~9 P4 h, w) o, v7 A' a. e: Q: k1 o& E- a
  U' s* D9 w& B3 E% A$ `( |0 y. t
Затем проверяем количество предметов (в данном случае количество клыков), и если их вообще нет, то возвращаем строку "Chat0.htm", если только один предмет, то возвращаем строку "Chat1.htm", если же предметов 4 или больше, то "Chat4.htm". Если строка возвращена из методов onEvent, onKill или onTalk, то сервер покажет соответствующие htm. В Chat0.htm может иметь следующий текст: «Вы не имеете ни одного клыка, возвращайтесь позже, когда соберете 4 штуки и бла, бла, бла…», в Chat1.htm может быть следующий текст: «У Вас всего 1 клык, по этому соберите еще…». В Chat4.htm – «Вы собрали необходимое количество предметов, возвращайтесь к вашему тренеру, что бы завершить квест…»( r# T* e/ v; H/ n- O( R
4 F( \' k; i  T3 ~* w
. O, G8 X: n: X; N/ V3 X* L
Примечание: если в строка return начинается с "<html>", то будет показана страничка html с текстом, который стоит далее. Так вместо:! [* L* p8 V4 a: H8 R) \0 d
return "Chat4.htm", t, s) B) P5 E: h

" {# ~# s0 ]. Y' g
+ k+ u8 H, a: ^* h8 P' [5 P
можно поставить:$ v3 m* N$ Y( @8 N* {# V
  1. return "<html><body>Return to your trainer to complete the quest</body></html>"
Скопировать код
Так же если строка заканчивается без .htm или в начале нет <html>, то текст будет выведен, как системное сообщение в окне чата. В нашем случае мы сделаем так, что бы при каждом убийстве keltik выводилось системное сообщение: «Собрано N из 4-х клыков».
4 z- a& N, L/ g; A; c0 L8 `' t8 M/ X, E/ \2 F! P* r( s6 M

: j  o! w6 o# H0 ]  ~3 R; L4 m& SНаш код для onKill имеет один недостаток. Он будет постоянно показывать Chat0.htm, Chat1.htm и Chat4.htm, нам же необходимо, что бы Chat0.htm и Chat1.htm показывались только один раз. Как нам это сделать? С помощью переменных.
/ g0 D' ~) p* M$ \, Y4 J) ?; h

- h6 K1 C! _0 P% \+ KВ каждом квесте строки могут храниться с помощью переменных. Эти переменные сохраняются в Вашей БД. В каждом методе мы можем назначить, прочитать и удалить переменные. Давайте изменим метод onKill, так что бы каждый диалог вызывался только один раз.
: y. O/ a2 [+ O5 @% J
  1. def onKill (self,npcId,st):
    9 B, `+ z: B3 [, c1 z) {* T
  2. if npcId == KELTIR_NPC_ID:
    & ^6 h* w: F. L# F& U$ j5 i1 a9 i6 _
  3. n = getCount(st)
    . k- e, X; d' G0 m; N8 @, _
  4. if n == 0:
    6 P) F9 U% {6 t
  5. if st.get('chat0') == None :
    % }. w' \- g$ P% u' w+ ^
  6. st.set("chat0", "true")6 @/ H1 d1 X$ Z7 L/ Q
  7. return "Chat0.htm"6 j  [0 }( f8 T% Z( V" i0 Q
  8. elif n == 1:
    ( A7 h! E( O' E9 ?4 E- Y# F
  9. if st.get('chat1') == None :
    ( w- T. `/ p/ X, f! ?7 |# V
  10. st.set("chat1", "true")
    ) P4 M, Y, B' L2 }% n# d
  11. return "Chat1.htm": Q0 i3 Y6 K" ?, q9 K6 [
  12. elif n >= 4:
    + A  Y9 T" |( \! Z% v
  13. return "Chat4.htm"* o1 L% J* O! V6 j& ]" `
  14. return "Collected "+str(n)+" of 4 fangs"% E3 O/ s  n. m" z3 H
  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.: X# c7 L% I: F/ E/ v6 f% ^: N& k, _
# \! B7 q( O; N8 N8 r9 `

  Z, U- {0 G# dВот конечный рабочий вариант квеста:; d" K5 [) d$ [: `
  1. import sys
    5 G. P% o% [& c/ K/ s
  2. from net.sf.l2j.gameserver.model.quest import State
    0 N# \4 }- h5 y2 D* T9 F
  3. from net.sf.l2j.gameserver.model.quest import QuestState
    7 V' p) c$ ^8 K4 P) o
  4. from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest+ j, W# l7 r8 T& q

  5.   Y$ U' k/ {( \6 M# g" f- @
  6. KELTIR_NPC_ID = 12082+ y6 n' ]) Q( Q- C5 ]
  7. FANGS_ITEM_ID = 1859( k/ n/ X; w# K$ @# a+ p* d8 z
  8. DROP_RATE    = 500000
    ! G- S+ n& I1 z* i
  9. 4 T6 C) N" P) n- a7 ^2 D
  10. WORLD_MAP_ITEM_ID = 1665+ f* Z/ L$ }4 x

  11. 0 e  Y  e( Y' h5 O$ b, r0 O
  12. def getCount(st) :/ c- I8 K, ^, v& K0 v  x
  13. return st.getQuestItemsCount(FANGS_ITEM_ID)6 C: s3 \7 m9 U6 K% k

  14. - k4 U7 \. l6 s, b7 u
  15. def completed(st) :
    0 Z: K  q! @( T1 ^, J# H
  16. st.setState(COMPLETED); K" e+ O# W$ V! o' j( \. i5 h
  17. st.clearQuestDrops()7 T5 L; B! n0 H: k' {- _4 F: ~
  18. st.takeItems(FANGS_ITEM_ID,-1)
    $ t6 s4 x- A4 e
  19. st.giveItems(WORLD_MAP_ITEM_ID,1)8 K5 y5 T) j' r9 f2 w- H0 |
  20. st.exitQuest(False). m; R, i+ i# D
  21. return
    % Q$ Z; z( b" d- o/ z% S8 b7 G
  22. + J6 T! f1 F; W! R$ G
  23. def check(st) :2 N( V9 X9 X% ?/ g/ E+ w$ P
  24. if getCount(st) >= 4 :0 k; [6 X7 o) |/ H
  25. completed(st)
    4 O( {" J8 c5 ?! L7 p+ `& M7 |
  26. return
    ) p; k* \9 b. h! K5 Y. y$ W

  27. , ?0 N6 _; H* X9 y* q6 [7 z
  28. class Quest (JQuest):1 L6 _( Z+ J: d2 ^: e
  29. / G! x+ ?8 p/ i/ D4 M1 c7 k4 T
  30. def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)
    9 L- x. I) k4 @+ A* n6 m

  31. - |  l* a+ b, [6 @$ N% C4 v% b
  32. def onEvent (self,event,st):. }# k6 u* A, i3 E  j
  33. id = st.getState()
      l' @% o) l  r' X) z
  34. if id == CREATED : st.setState(STARTED)5 m# }1 `. Z2 F$ ]0 t% N
  35. elif id == COMPLETED: pass! K5 S' y/ R: C( u/ W
  36. elif id == STARTED : check(st)' V  k, c+ _5 r7 j/ ~
  37. return
    * ?. W8 U' U0 U. f( h" M; L

  38. 3 s2 R/ b/ p* Z* w0 @
  39. def onKill (self,npcId,st):
    ; b* {+ d  ]9 L( |* c( N" ^
  40. if npcId == KELTIR_NPC_ID:* w; ?) l5 M7 {+ O" X# N9 b2 @
  41. n = getCount(st)- F- v5 n8 b& V, p, K
  42. if n == 0:
    ! ^) y4 b6 b& i/ {
  43. if st.get('chat0') == None :
    5 M. V5 E; J4 o" y. K+ @
  44. st.set("chat0", "true")) ?- P% a5 I0 b# Y# r+ S8 G1 h
  45. return "Chat0.htm"% x! v9 [+ g6 }! V. [" V
  46. elif n == 1:
    : ^: c/ Y* r. P+ \: l4 p% H
  47. if st.get('chat1') == None :
    6 K! W# j5 z  ?3 A- ]( m
  48. st.set("chat1", "true")
    , e! r$ `; u0 L  _+ X
  49. return "Chat1.htm"
    - k7 w! `2 ?$ z! R" k
  50. elif n >= 4:
    , X/ {% ~2 Y. b8 y7 d4 m1 v9 c6 f$ l
  51. return "Chat4.htm"
    " J8 J  g3 g' }5 |( J; P# g/ D7 o
  52. return "Collect "+str(n)+" of 4 fangs"  @6 |4 u1 y; b2 L# q- v# q( w2 z% u6 I
  53. return
    ( I! V; E4 [( Z: Y  g

  54. ( Q! H6 _' |3 O  z0 m: l, B9 a
  55. QUEST    = Quest(201, "Tutorial", "Tutorial quest")
    ; K) d. @: W# s1 ^
  56. CREATED = State('Start',    QUEST)" e) A" R$ N; O5 s! @
  57. STARTED = State('Started', QUEST)
    ! I0 G7 |9 |# d  B6 x; y3 j) l& q
  58. COMPLETED = State('Completed', QUEST)
    + J% X, U5 K+ R. a1 e* ~9 J

  59. : x; R1 T  O/ Y0 p, i/ K! X/ D( {9 o
  60. QUEST.setInitialState(CREATED)
    . M" u! k/ ?( G9 f" L# C
  61. QUEST.addStartNpc(7056)% @- u: i; u' z, y! H7 v" z
  62. QUEST.addStartNpc(7012)$ m% X" A) h" a$ X: D! D! K
  63. QUEST.addStartNpc(7009)
      K, h5 g1 c* u2 w
  64. QUEST.addStartNpc(7011)+ H% w* b: e2 J/ ~" `4 W) |
  65. " {. g7 N+ U$ d' s0 g* S
  66. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
    6 _  ~6 _& |% \6 c  g  _9 {7 L- H
  67. STARTED.addKillId(KELTIR_NPC_ID)+ _7 G; r& w5 v6 ~9 Z
  68. STARTED.addTalkId(7056)
    4 A0 b4 {1 k7 H8 W' W
  69. STARTED.addTalkI d(7012)! W# W" I; A/ B- n
  70. STARTED.addTalkId(7009)
    " C( E8 k3 C3 V9 _
  71. STARTED.addTalkId(7011)
Скопировать код
4 ~* }6 f9 {& B2 P: g& h2 v, x
$ Y' j9 Z8 h( U; f8 i3 H( |





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