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

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

Автор: admin    Время: 2024-9-17 19:36
Название: Создаём собственные квесты (часть 2)
Хроники        Interlude
- e7 H5 o0 F. _Сборка        L2j! p5 {5 E9 Z6 n' H6 P6 n! R, s& z
Обратите внимание: в файле htm стартового NCP обязательно должна быть ссылка на квест:
  \$ Y  s4 t% n# ?
  1. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста:! v5 v; V9 C5 M" H

- Z  S, a- S6 O
  1. if getCount(st) >= 4 :4 u1 j# w/ {, `& e
  2. completed(st)& z# d) Q+ b6 i3 ?( s
  3.   return
    8 n* i4 B1 f! u+ }5 ?

  4. & W$ D/ \) w. e. l( [! n: `, d  F
  5. class Quest (JQuest):
    4 z, i5 M! z! [
  6.   def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)
    ! n" M& I3 _; M0 f! g
  7.   def onEvent (self,event,st):! M. Q/ q4 M; G  f* e( x% o5 x
  8. id = st.getState(), F: {- @: `2 r% @) n
  9. if   id == CREATED  : st.setState(STARTED)
    : Q6 K3 I- D, f! j& z2 S8 B
  10. elif id == COMPLETED: pass
    3 C$ W/ G" Y2 y
  11. elif id == STARTED  : check(st)# ?# y) O7 z3 z( ^  v& V9 W
  12. return- G. c8 f9 `' g4 L# S" v

  13. 2 P4 V6 ?$ ]; l. z% Q$ P3 d& O
  14. QUEST     = Quest(201,"Tutorial", "Tutorial quest")# }  _. Z& x& ~0 N" w: x4 v& K
  15. CREATED   = State('Start',     QUEST)
    0 o* e+ ?9 o& Z+ p! B+ ]3 X" T( l
  16. STARTED   = State('Started',   QUEST)
    - {$ ]7 c1 ?% I" b9 H7 T
  17. COMPLETED = State('Completed', QUEST); x' x4 t* ?( v/ p

  18. 2 I4 c4 H1 Y2 A8 o+ G
  19. QUEST.setInitialState(CREATED)
    / O# [0 a/ H" e; q8 m1 P# L( i1 I
  20. QUEST.addStartNpc(7056)% m3 A6 A- ^( u6 j5 N; R
  21. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Теперь рассмотрим, как это работает.
& j7 j6 w* T9 Q  X3 P0 zИгрок подходит к начальному NCP (в данном случае 7056), нажимает на «Quest». Квест будет создан и состояние квеста перейдет к CREATED и игроку будет показана страничка Start.htm с описанием квеста. Тогда метод onEvent, поле открытия странички Start.htm переведет состояние квеста в STARTED и игроку будет показана страничка Started.htm, где будет опсание того, как найти keltirs и .т.д.( p; V! |" q7 E9 }) {7 N

7 C! J. E2 E8 j- Y+ ]
+ T2 {* r/ W' x: `, V
При состоянии STARTED будет зарегистрирован дроп «fangs» при убийстве keltirs. Игрок может вернуться к стартовому NCP и спросить о квесте – метод onEvent будет вызван снова. Если у игрока не хватает необходимого количества предметов, то метод check() не переведет квест в следующее состояние и Started.htm будет показана снова. Но если игрок собрал необходимее количество предметов (в данном случае 4 клыка), то метод check() вызовет метод completed() который переведет квест в новое состояние COMPLETED, заберет все клыки, даст карту мира, т.к. это награда за квест, покажет Completed.htm и завершит квест.1 t1 x. s3 \4 x" P2 Q6 }) G' ^1 \2 V

  |3 d% A; F' [8 R" ~% G4 @
3 n: O, I8 R$ G% E
Теперь давайте сделаем наш квест более похожим на то, что он должен из себя представлять.
8 D: U' e2 d- tПрежде всего у нас есть 3 метода для объявления их в Яве – onTalk, onKill и onEvent. Если методы onTalk и onKill не объявлены, то за них все будет делать метод onEvent, т.е. определять квестовых монстров и вызывать диалоги NCP. Есть примечание, методы onTalk и onKill будут вызывать только диалоги с NCP в зависимости от текущего состояния квеста. Метод onKill будет вызываться только тогда, когда мы убиваем квестового монстра.( l& o8 `1 z5 R! S; k' H

. o' F9 J' _5 o! b

. @: S3 P6 }4 WДавайте рассмотрим как вызывается метод onKill при убийстве keltir в состоянии квеста STARTED:0 a+ v1 z0 V6 t& ^  b) Z1 X
  1. STARTED.addKillId(KELTIR_NPC_ID)
Скопировать код
и метод onKill в классе Quest:
. S! J0 L( k: d% k: S/ [; X1 k( o' `/ D4 ~0 w' _% i
  1. class Quest (JQuest):
    ' ?4 v! a) I; Q. ]
  2.   ...
    . `- [2 W! [9 g, m
  3.   def onKill (self,npcId,st):
    1 H; s. c5 p2 r* K
  4. if npcId == KELTIR_NPC_ID:* V6 W5 M) Z0 e
  5.    n = getCount(st)
    % ], {+ G, Q: `
  6.    if   n == 0:7 j1 x5 D- H/ A" s
  7.        return "Chat0.htm"# Z8 T' i( ^2 f  ~8 B
  8.    elif n == 1:! J/ b' m8 d0 |3 f" \. h
  9.        return "Chat1.htm"
    ' r& V0 `! m; d& w' w
  10.    elif n >= 4:
    ' C; @8 G8 V# l/ |) r% E% }. X
  11.        return "Chat4.htm"5 o% A! @. ^4 K/ t3 K9 t  m
  12.    return "Collected "+str(n)+" of 4 fangs"2 l: Y7 \4 a2 [9 y- Z
  13. return
Скопировать код
Метод onKill (а так же метод onTalk) имеет следующие параметры:
4 A. y9 D& t9 h+ x9 e
: E" D7 j2 L* W% Y( K2 e
. J+ X0 Q  d* H
• self – квест
3 Q  u. o# O8 i2 W- k• npcId – ID NCP, которого мы должны убивать (если это метод onTalk, то ID того NCP, с которым мы должны поговорить).
7 b3 o! Q' d4 P• st – текущее состояние игрока.0 R* B' b) o5 J. Z6 w- W
: ]- B2 D8 r$ p  Q  d  E5 D$ h' l4 ^2 W
% G  o* ~* u9 a. g; e5 H8 M. p
В этом методе мы проверяем и отмечаем, является ли убитый NCP keltir’ом. В основном эта проверка не нужна, т.к. у нас только KELTIR_NPC_ID.0 T+ M4 ]2 W/ _5 s
! {& A9 Q: p' Q/ F% ]7 J8 W9 E

5 _% }% ?  {2 a$ n! MЗатем проверяем количество предметов (в данном случае количество клыков), и если их вообще нет, то возвращаем строку "Chat0.htm", если только один предмет, то возвращаем строку "Chat1.htm", если же предметов 4 или больше, то "Chat4.htm". Если строка возвращена из методов onEvent, onKill или onTalk, то сервер покажет соответствующие htm. В Chat0.htm может иметь следующий текст: «Вы не имеете ни одного клыка, возвращайтесь позже, когда соберете 4 штуки и бла, бла, бла…», в Chat1.htm может быть следующий текст: «У Вас всего 1 клык, по этому соберите еще…». В Chat4.htm – «Вы собрали необходимое количество предметов, возвращайтесь к вашему тренеру, что бы завершить квест…»3 A! z1 l- E9 x
: x8 R# I* V* G

* S2 q% k7 H- N: }2 l1 AПримечание: если в строка return начинается с "<html>", то будет показана страничка html с текстом, который стоит далее. Так вместо:- i  c. H7 @" }, v5 T: u" h
return "Chat4.htm"
: n  h2 q; R! T+ ^4 D
1 @3 n( b" t9 k- O' m1 E% t0 m0 a

& m3 m# l+ c! h: G; b+ Uможно поставить:% H+ j' b7 C) ?9 ?. B) d
  1. return "<html><body>Return to your trainer to complete the quest</body></html>"
Скопировать код
Так же если строка заканчивается без .htm или в начале нет <html>, то текст будет выведен, как системное сообщение в окне чата. В нашем случае мы сделаем так, что бы при каждом убийстве keltik выводилось системное сообщение: «Собрано N из 4-х клыков».
9 k0 }. ^" H6 Z( @7 @, u
" t9 D# m6 A1 k- h7 o4 p* ?

/ i8 G0 u' v8 V) `4 c3 u0 U  HНаш код для onKill имеет один недостаток. Он будет постоянно показывать Chat0.htm, Chat1.htm и Chat4.htm, нам же необходимо, что бы Chat0.htm и Chat1.htm показывались только один раз. Как нам это сделать? С помощью переменных.- p" }7 t* ^: h+ {8 \6 I. Z

4 C' B! m/ z% L. w8 U1 K

3 {# `8 I7 \6 ^В каждом квесте строки могут храниться с помощью переменных. Эти переменные сохраняются в Вашей БД. В каждом методе мы можем назначить, прочитать и удалить переменные. Давайте изменим метод onKill, так что бы каждый диалог вызывался только один раз.2 D7 b% C3 ?/ |* o- W
  1. def onKill (self,npcId,st):
    + L" x1 U+ M# s( [& r
  2. if npcId == KELTIR_NPC_ID:" I( L5 ^. ^! D* V4 Q( z
  3. n = getCount(st)& B* ~7 d( F9 j& e* [
  4. if n == 0:  I  G: p5 S2 f( j4 j3 V; m' i) g
  5. if st.get('chat0') == None :" V$ k: i3 t7 a1 y1 B, z5 f( r
  6. st.set("chat0", "true")
    * {4 s9 K2 S; t; _, u$ b3 V9 S+ _
  7. return "Chat0.htm"$ {' F! C! J  @: _  ^+ N' v  `
  8. elif n == 1:
    7 P' ?5 e- h! i
  9. if st.get('chat1') == None :
    + F. I8 ^! L/ b, x3 H  o' A) z
  10. st.set("chat1", "true"); b: [1 O2 [  Q4 V  ^5 [
  11. return "Chat1.htm"
    ) `* N: k) Z& D4 {# O
  12. elif n >= 4:
    ; Z' Z" q; f8 u9 M- Y3 s  G
  13. return "Chat4.htm"9 D* j/ C" Y* o+ g# ]: g
  14. return "Collected "+str(n)+" of 4 fangs"
    $ ]3 ]$ a. b! K, O+ r
  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.
/ M8 g# ^' \4 f+ Y2 |, a
/ a4 B# K7 {% L. ]  ~

  _# e) L2 _$ V5 `- x: [Вот конечный рабочий вариант квеста:
) r( {2 Y( S+ N; m, C! K; r
  1. import sys5 Y3 K8 f/ M* f! O1 N
  2. from net.sf.l2j.gameserver.model.quest import State1 l4 M" V/ F7 e
  3. from net.sf.l2j.gameserver.model.quest import QuestState
    0 `4 O# z  o( ^/ P7 ~6 P/ J- W
  4. from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest
    ' {; d4 [0 }: I+ t( p1 V# @4 Y

  5. % W, j* ~6 v8 v- X
  6. KELTIR_NPC_ID = 12082
    4 }% f0 S& q) l3 w1 ?  O: O
  7. FANGS_ITEM_ID = 1859
    ; W% f0 H+ b" n$ Q" W' V
  8. DROP_RATE    = 500000
    6 g  z8 Y+ u  s) \" V2 \/ q. I' R

  9. ( o! E# d& X2 I$ R1 v
  10. WORLD_MAP_ITEM_ID = 1665$ q" j9 K# r( f5 I
  11. ' R$ Q3 Z) L: K! P
  12. def getCount(st) :7 M) @- f, \' J5 }& ~
  13. return st.getQuestItemsCount(FANGS_ITEM_ID)
    9 K' O$ m+ Y& k, C8 t# M8 U1 ~

  14. : C' d! {% P) ^
  15. def completed(st) :
    : \6 T2 m& f/ [6 s% [
  16. st.setState(COMPLETED)
    6 t9 b5 O0 Y. X  ?
  17. st.clearQuestDrops()
    + j/ Q" v: {6 W6 @
  18. st.takeItems(FANGS_ITEM_ID,-1), R% B  v. n  M3 J3 a
  19. st.giveItems(WORLD_MAP_ITEM_ID,1)% J4 O6 D: O) c: R8 q- a& a) P- I
  20. st.exitQuest(False)) o. g( t" y" J6 c1 `3 Z
  21. return' N3 i# \4 B% W, M- F
  22. 8 b4 z( D& ?$ C0 X8 y: G7 L! R
  23. def check(st) :3 A6 o7 U0 `# r8 c
  24. if getCount(st) >= 4 :
    0 E6 I; _- ~' \* X# j
  25. completed(st)
    8 q+ t' G; |. c: g% t# f  `
  26. return
    * s) D! ^& X, E" j7 G0 D& X2 W

  27. 2 Y/ R0 Z/ s+ @9 b9 M6 @
  28. class Quest (JQuest):
    & B0 u, M( {$ k7 b2 _3 ^: k* Y

  29. ! ~. r- X% m. r( X" u: @
  30. def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)* |7 j( P8 T9 m' F1 h
  31. + s% `9 K1 k+ B, D+ g5 M6 i
  32. def onEvent (self,event,st):
    + E" O/ v* N; k/ N1 `; B
  33. id = st.getState(); T6 I' t! [& A+ o
  34. if id == CREATED : st.setState(STARTED), p5 h( g" }& R. L
  35. elif id == COMPLETED: pass
    ( o& S2 \& m* }6 J$ Z1 h) b! a: o
  36. elif id == STARTED : check(st)
    / U; q% t- `7 K) ~% @$ P" _
  37. return
    ' P. Q. b% i! O; N- I
  38. # X! y" V5 C: C: F0 V3 V
  39. def onKill (self,npcId,st):
    ! y2 i& G% B8 r# R' L4 O3 ]
  40. if npcId == KELTIR_NPC_ID:
    . q. q' {+ n$ v- a
  41. n = getCount(st)
    3 H2 z* H( e8 c( |: l) t+ L
  42. if n == 0:  ]+ m3 K: l/ ]  A. A% }& O
  43. if st.get('chat0') == None :
    5 N- [3 ^  K' G+ H* v5 m+ x+ K
  44. st.set("chat0", "true")
    0 H  c& G, B3 ^5 y) e6 H1 T
  45. return "Chat0.htm"+ A7 F% D) B% A. k, v% r  O
  46. elif n == 1:
      z0 J9 M4 M  A0 L
  47. if st.get('chat1') == None :8 |  x3 z5 e  k8 z
  48. st.set("chat1", "true")
    * p& ~2 V& ^% y0 U7 v0 n; V
  49. return "Chat1.htm"
    - H; ]5 k6 z# E' R
  50. elif n >= 4:" d! |( i( ^/ e& x7 N6 x, _
  51. return "Chat4.htm"! ?3 b) p6 S0 q8 V
  52. return "Collect "+str(n)+" of 4 fangs"
    7 {& q, K2 Y1 p% i6 t$ Z
  53. return
    / @: c7 Z3 P2 d( _1 |" r
  54. + x' ?& W, t+ H- o; d% Z
  55. QUEST    = Quest(201, "Tutorial", "Tutorial quest")
    + u# b* \; ?7 Y" d+ g1 Y# L' I
  56. CREATED = State('Start',    QUEST)1 @; E" b; n' A& Q
  57. STARTED = State('Started', QUEST)/ j% z5 J% |& L
  58. COMPLETED = State('Completed', QUEST)
    ' z! F! O2 P, |  J" e

  59. ' r3 L+ p, g/ n( H) B% B, P+ w$ F/ X
  60. QUEST.setInitialState(CREATED)$ B; y+ m2 S' j
  61. QUEST.addStartNpc(7056)
    4 K1 C7 O' L; L1 G2 Y
  62. QUEST.addStartNpc(7012)
    6 Q' m  q; D# }* D* |" a0 F: [
  63. QUEST.addStartNpc(7009)+ h& n! I  b5 _4 _) D- U2 j, S
  64. QUEST.addStartNpc(7011): r2 B! C7 z% I& i- ]' L
  65. # M+ u; X  d0 L3 T
  66. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)- w5 h7 O% P. w- ~4 A
  67. STARTED.addKillId(KELTIR_NPC_ID)& S. X" b+ x  D" J2 O
  68. STARTED.addTalkId(7056)
    : Q( G/ r$ ~$ K% A; W# k' i
  69. STARTED.addTalkI d(7012)4 d+ c: w' Q+ H3 I; G9 D6 w
  70. STARTED.addTalkId(7009)
      F( i/ \* I- b. t* g
  71. STARTED.addTalkId(7011)
Скопировать код
2 c- t* \9 M4 k7 l

. p) o9 V  ]% b* \




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