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

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

Автор: admin    Время: 2024-9-17 19:36
Название: Создаём собственные квесты (часть 2)
Хроники        Interlude
# n3 O. K. H2 ?Сборка        L2j
! y+ S" k6 Z) @( ]) V. eОбратите внимание: в файле htm стартового NCP обязательно должна быть ссылка на квест:  Z% n8 O9 V5 l" T2 I1 q
  1. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста:
7 k8 B* E7 y* |" t& ^/ x) L1 I* ]" ?( ?) P7 H( N- T9 D+ B; t
  1. if getCount(st) >= 4 :
    . o# n; c& ^6 a  p! _9 g4 h  [
  2. completed(st)
    4 R6 U$ }$ U5 _: Z& h0 U, a, u
  3.   return
    + S) i0 G  |% p+ x; n' Q

  4. ! o% V+ V8 p9 x1 [( x: a5 N
  5. class Quest (JQuest):
    1 J) g8 y4 V& V6 g4 d) ]
  6.   def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)  u6 H) y2 T6 |7 E  \
  7.   def onEvent (self,event,st):" u+ V: f' r4 u8 l* Q" m# \
  8. id = st.getState()  P0 I+ p; c* D3 U7 ^8 I' G4 ]7 F, v
  9. if   id == CREATED  : st.setState(STARTED)
    ! N; P# k$ ^9 `' c; y/ o  K
  10. elif id == COMPLETED: pass( g. y* D& b3 C4 c, M, D8 |8 H
  11. elif id == STARTED  : check(st)5 l; ^1 D' C) h/ R8 @; U
  12. return
    3 i" e0 ^* Z1 ?. o: ]* P& w' D
  13. 1 a4 m5 c" Q% P$ [& _
  14. QUEST     = Quest(201,"Tutorial", "Tutorial quest")
    8 P. i( B6 ~4 l2 N7 K, {5 U2 [
  15. CREATED   = State('Start',     QUEST)
    % o  X" F; ]; x1 _$ s' p$ m" Q5 v
  16. STARTED   = State('Started',   QUEST)
    1 r. B7 D+ D0 S6 b% F9 L
  17. COMPLETED = State('Completed', QUEST)6 R8 {" W- f$ d3 a1 G+ m
  18. + Z* K4 d/ X# k. L- T* ~1 @
  19. QUEST.setInitialState(CREATED)
    3 C7 s8 W+ }) m
  20. QUEST.addStartNpc(7056)
    9 H5 b5 k$ |$ i5 k: @2 j6 l
  21. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Теперь рассмотрим, как это работает.8 ?) P+ w. @# i" L  R' D* P
Игрок подходит к начальному NCP (в данном случае 7056), нажимает на «Quest». Квест будет создан и состояние квеста перейдет к CREATED и игроку будет показана страничка Start.htm с описанием квеста. Тогда метод onEvent, поле открытия странички Start.htm переведет состояние квеста в STARTED и игроку будет показана страничка Started.htm, где будет опсание того, как найти keltirs и .т.д.
& s  I( r9 C, y4 J7 w& L. a
& Z; e; C, Z) p, U* ^, [

# i; F2 d! D, r5 Y6 x. U& VПри состоянии STARTED будет зарегистрирован дроп «fangs» при убийстве keltirs. Игрок может вернуться к стартовому NCP и спросить о квесте – метод onEvent будет вызван снова. Если у игрока не хватает необходимого количества предметов, то метод check() не переведет квест в следующее состояние и Started.htm будет показана снова. Но если игрок собрал необходимее количество предметов (в данном случае 4 клыка), то метод check() вызовет метод completed() который переведет квест в новое состояние COMPLETED, заберет все клыки, даст карту мира, т.к. это награда за квест, покажет Completed.htm и завершит квест.
% L+ P$ G: G  p7 G6 }: Y$ B: X
6 _! q  i7 W- z6 f) X4 H' f) M

% f, m1 p1 Q/ _1 C7 uТеперь давайте сделаем наш квест более похожим на то, что он должен из себя представлять.
+ r( T& }1 e3 c5 o( |+ ~Прежде всего у нас есть 3 метода для объявления их в Яве – onTalk, onKill и onEvent. Если методы onTalk и onKill не объявлены, то за них все будет делать метод onEvent, т.е. определять квестовых монстров и вызывать диалоги NCP. Есть примечание, методы onTalk и onKill будут вызывать только диалоги с NCP в зависимости от текущего состояния квеста. Метод onKill будет вызываться только тогда, когда мы убиваем квестового монстра.3 H. `' B1 }  x- f* n
! K3 D) s# ~8 }; k

; n6 E/ ?; x8 s$ D0 }/ ?Давайте рассмотрим как вызывается метод onKill при убийстве keltir в состоянии квеста STARTED:* w' `( W. c  ~. g0 |. r2 I8 l$ O
  1. STARTED.addKillId(KELTIR_NPC_ID)
Скопировать код
и метод onKill в классе Quest:% g. N$ T, q7 C* G: C

+ Y5 O7 w3 ?& Y4 i
  1. class Quest (JQuest):
    ) ?- v& q! z- H" _" l" s
  2.   ...3 {3 g0 a$ n: P! Q& e
  3.   def onKill (self,npcId,st):
    & a) b- x$ t2 T/ q; F6 ?3 M
  4. if npcId == KELTIR_NPC_ID:, c4 s8 A" M! a3 e5 d8 ]
  5.    n = getCount(st)
    4 d7 z$ p- ]1 n8 k4 D2 [5 O/ I
  6.    if   n == 0:  R+ t) J7 Y( Y  c" V
  7.        return "Chat0.htm"
    ! P4 R" [6 O. ~
  8.    elif n == 1:; X. n+ h- d* A% G& e1 \7 B9 ?
  9.        return "Chat1.htm"
    # X. O# ?& u7 W* N+ j
  10.    elif n >= 4:
      M' p9 F$ W  B  w' J4 P/ Z
  11.        return "Chat4.htm"# }$ j- a) a' E# Y& f. t/ S/ S3 z
  12.    return "Collected "+str(n)+" of 4 fangs"
    / z. G1 ?9 s# C7 A4 U6 o
  13. return
Скопировать код
Метод onKill (а так же метод onTalk) имеет следующие параметры:
5 s' E" B! V7 W# o: q: K/ ~( u+ Q: U- \! k

+ U3 R7 O. P' p• self – квест
! I/ F. J5 L) G9 F5 [/ v• npcId – ID NCP, которого мы должны убивать (если это метод onTalk, то ID того NCP, с которым мы должны поговорить)./ l6 l) w" f  J* f9 I1 S' d
• st – текущее состояние игрока.
) s; b" f& _8 i# a0 L! B
- W6 A0 v: E! V$ X0 r( E

  B" ~4 p5 {6 ?# r! L* dВ этом методе мы проверяем и отмечаем, является ли убитый NCP keltir’ом. В основном эта проверка не нужна, т.к. у нас только KELTIR_NPC_ID.
/ V; q" ?' |, I- k* M2 [9 O9 B5 K) r8 h0 ]+ O2 Z

3 [' B6 Y& _2 z- n9 wЗатем проверяем количество предметов (в данном случае количество клыков), и если их вообще нет, то возвращаем строку "Chat0.htm", если только один предмет, то возвращаем строку "Chat1.htm", если же предметов 4 или больше, то "Chat4.htm". Если строка возвращена из методов onEvent, onKill или onTalk, то сервер покажет соответствующие htm. В Chat0.htm может иметь следующий текст: «Вы не имеете ни одного клыка, возвращайтесь позже, когда соберете 4 штуки и бла, бла, бла…», в Chat1.htm может быть следующий текст: «У Вас всего 1 клык, по этому соберите еще…». В Chat4.htm – «Вы собрали необходимое количество предметов, возвращайтесь к вашему тренеру, что бы завершить квест…»! O% u# p+ Q2 f- F6 Z1 \

0 u0 g/ u: G* m6 A; `! e; N# y
' `" ]: _- r+ U1 K# f( d
Примечание: если в строка return начинается с "<html>", то будет показана страничка html с текстом, который стоит далее. Так вместо:3 n; H; s+ }& K
return "Chat4.htm"
3 @" {. x& }* u0 K0 ]
8 s. N  n0 F- |" P7 ^* |$ y
9 L6 F/ q) }6 M9 Z
можно поставить:8 p6 {0 x' H) j1 W* y& V
  1. return "<html><body>Return to your trainer to complete the quest</body></html>"
Скопировать код
Так же если строка заканчивается без .htm или в начале нет <html>, то текст будет выведен, как системное сообщение в окне чата. В нашем случае мы сделаем так, что бы при каждом убийстве keltik выводилось системное сообщение: «Собрано N из 4-х клыков»." t5 D9 d; `$ B9 ?% O4 ?  Q; S) Y

4 \4 F8 O% I  c

% z. n" T$ _* T* n% _$ aНаш код для onKill имеет один недостаток. Он будет постоянно показывать Chat0.htm, Chat1.htm и Chat4.htm, нам же необходимо, что бы Chat0.htm и Chat1.htm показывались только один раз. Как нам это сделать? С помощью переменных." p" d3 N; {0 g* @
5 ^) q* v) Q9 j
4 C0 Q  p9 p# q3 c5 b
В каждом квесте строки могут храниться с помощью переменных. Эти переменные сохраняются в Вашей БД. В каждом методе мы можем назначить, прочитать и удалить переменные. Давайте изменим метод onKill, так что бы каждый диалог вызывался только один раз.: K5 Z1 P) T, o$ y. I
  1. def onKill (self,npcId,st):3 P+ L" R& }2 r+ `' `& [5 J
  2. if npcId == KELTIR_NPC_ID:
    4 ?# Z, d8 I# P
  3. n = getCount(st)7 X& B2 m4 I# M  k" v
  4. if n == 0:
    $ X: v- j; }+ G7 F* a# G
  5. if st.get('chat0') == None :
    ( T. D/ p8 ~; j: s8 O
  6. st.set("chat0", "true")1 S+ `9 ]  I* Z4 P7 x. |, K
  7. return "Chat0.htm"
    + I9 V" b# h' I: F" z
  8. elif n == 1:; }( z8 O1 m# H0 O% X
  9. if st.get('chat1') == None :/ \3 N( A4 T0 p% {6 ^0 f5 ]. m$ J6 t0 T
  10. st.set("chat1", "true")
    6 |, l) [3 }% l# m: _, `5 V/ J
  11. return "Chat1.htm"- U9 ^: I6 {' ?  |5 W' q
  12. elif n >= 4:
    . s1 b$ C. A6 Y7 |9 O
  13. return "Chat4.htm"
    + E3 A# ^1 a+ L" U
  14. return "Collected "+str(n)+" of 4 fangs"
    ( N- ]! e4 [% A
  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.& \9 z$ T8 @2 @$ A$ d8 q
! s0 S4 Q, A7 `
$ m% Q7 W; w3 h* T
Вот конечный рабочий вариант квеста:
+ W" N  K  F7 u- E- P
  1. import sys3 L+ s2 t3 _- Y- I1 v
  2. from net.sf.l2j.gameserver.model.quest import State
    & i+ L' m; A8 a, x' O: E( b) w' n
  3. from net.sf.l2j.gameserver.model.quest import QuestState- k8 y6 V9 Y8 j7 r
  4. from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest
    ) A& y0 ~/ Z  G% V

  5. 7 K3 s/ v2 R: F6 C" r- @: Y
  6. KELTIR_NPC_ID = 12082
    ! P2 x: I$ P$ v# i
  7. FANGS_ITEM_ID = 1859
    : Z+ w( ~7 i. k
  8. DROP_RATE    = 500000$ r8 U2 G: l4 a5 v$ ^; _
  9. 8 c) W3 I) K0 q
  10. WORLD_MAP_ITEM_ID = 1665
    4 H9 v! u$ ]: h
  11. 2 H% A7 B% [. v, [7 E* j
  12. def getCount(st) :% {9 V5 E2 [4 a, g& ?+ o5 M2 B
  13. return st.getQuestItemsCount(FANGS_ITEM_ID)# Q3 `. a: q: W) R) ?7 ^0 U, I
  14. 5 U4 ?) }' V- `4 \- R
  15. def completed(st) :
    ' y; {% H1 O- z% ]; H: g
  16. st.setState(COMPLETED)& X( G% A) M& a4 v& j# c' l
  17. st.clearQuestDrops()
      R  `  F4 v* C% T& z: Q
  18. st.takeItems(FANGS_ITEM_ID,-1)
    # E7 g; c: |; K8 u1 f
  19. st.giveItems(WORLD_MAP_ITEM_ID,1)
    3 [+ g& ?4 q6 D; f# @
  20. st.exitQuest(False)$ Z* y* s* T  ~
  21. return9 h" V7 V2 |9 b9 N

  22. 9 _: a2 I* [# T$ y
  23. def check(st) :
    : w( U0 `9 m" d3 W2 Z8 q
  24. if getCount(st) >= 4 :
    1 ~- U) e, i8 N* K) C& i5 {2 Q
  25. completed(st)
    . f8 b7 N7 D7 ^2 ^5 }9 g
  26. return
    ) U' ?0 L* @9 u; O: D7 x
  27. , W, S3 w4 ]0 y8 i2 F& B% S
  28. class Quest (JQuest):/ p3 K' l% m& ]6 `. {3 i
  29. $ m3 y, Y% L# u! q( o4 z/ W
  30. def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)
    ! V1 D' l$ _- e7 b9 D
  31. 7 h) @6 B3 ~2 F3 Z# r
  32. def onEvent (self,event,st):1 c. V! K9 `1 c; C. w
  33. id = st.getState()# T: A" r/ n3 v5 n
  34. if id == CREATED : st.setState(STARTED)
    0 C( e/ t( N0 e" o+ I
  35. elif id == COMPLETED: pass) r2 d+ s3 t3 E# u, e* v4 z) j! t$ L
  36. elif id == STARTED : check(st)
    + ?$ }; M1 s) k
  37. return/ Q+ |) m: T0 n! r9 V: j3 d' U0 ~9 `

  38. ; a  a  G. l; R0 U0 L$ L0 N
  39. def onKill (self,npcId,st):
    ) H2 f$ Y7 i: r4 Q' `; H
  40. if npcId == KELTIR_NPC_ID:+ |6 r3 K5 k  d. p
  41. n = getCount(st)2 H7 {& ]2 X1 C2 y* L0 r* b
  42. if n == 0:4 p' K) T) `" A! d
  43. if st.get('chat0') == None :- b7 x4 w4 }/ O0 q$ y5 F
  44. st.set("chat0", "true"). l$ _$ J: e; A  v& p
  45. return "Chat0.htm"& U! I; Q! j; Y9 U; e/ g
  46. elif n == 1:
    6 q. J3 L' r4 j! y4 F
  47. if st.get('chat1') == None :
    6 Z1 {9 T/ Q; c
  48. st.set("chat1", "true")
    1 ~) I# n+ D& f0 j& C, o! J# F  c
  49. return "Chat1.htm"
    2 S/ F2 {# B7 c7 s" a# r
  50. elif n >= 4:
    ( f5 c) i8 X6 C; ]% n
  51. return "Chat4.htm"
    " j! H8 j, @! V# X( H. k
  52. return "Collect "+str(n)+" of 4 fangs"
    3 Q# z- T( X" l
  53. return- m( t) {' }6 w
  54. 2 k& u5 l0 Z& H$ P
  55. QUEST    = Quest(201, "Tutorial", "Tutorial quest")) O4 N/ K3 R! W" p
  56. CREATED = State('Start',    QUEST)) c! U- l1 }+ N$ u
  57. STARTED = State('Started', QUEST)
    ( ^) |  X; F2 S5 e( M5 R, C
  58. COMPLETED = State('Completed', QUEST)0 g7 j" y: Q, f/ K* ~

  59. , X+ H5 J' {# y2 Y6 c
  60. QUEST.setInitialState(CREATED)
    5 d% T5 Y4 P) x$ q0 D7 w
  61. QUEST.addStartNpc(7056)
    ( S+ y- W/ x. r3 V2 [" |& V
  62. QUEST.addStartNpc(7012)2 H4 K# k) `0 r# M9 h( f* H
  63. QUEST.addStartNpc(7009)
    ) o$ g7 t1 N  ]6 V! n  D
  64. QUEST.addStartNpc(7011)$ R, x+ F: Z# c) P0 v) N. p3 C
  65. 7 B4 ^+ U( p9 _& `9 Z. k' V5 j3 V
  66. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)3 z# z3 e3 z( B
  67. STARTED.addKillId(KELTIR_NPC_ID); G  M5 N: i' M7 b2 i/ q0 m
  68. STARTED.addTalkId(7056)
    + h( z7 X5 e, P2 K, R: \
  69. STARTED.addTalkI d(7012)0 F% @0 ~1 W: }% H, I
  70. STARTED.addTalkId(7009)
    $ ?0 u, X& K) Y) ~; V5 T5 o  K  b
  71. STARTED.addTalkId(7011)
Скопировать код

0 B& R( ~  w; r0 K+ m$ C
7 F/ r, h4 `3 O% H6 t5 n) p




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