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

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

Автор: admin    Время: 2024-9-17 19:36
Название: Создаём собственные квесты (часть 2)
Хроники        Interlude
# e) j& \% T; s/ c" G8 y/ c& b$ X; \- SСборка        L2j* y  t& B& K; e  S6 `; n) b
Обратите внимание: в файле htm стартового NCP обязательно должна быть ссылка на квест:# l* u1 p' g3 e/ k" \. z0 B9 w1 U
  1. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста:
- k7 R/ P. Y/ E' s* F5 n5 H6 n1 A4 _3 P. u
  1. if getCount(st) >= 4 :
    " d6 r3 Q5 M" Y- Y+ |' L
  2. completed(st)) u2 `7 m0 r! A; w( B# a
  3.   return$ u3 @; [" C( _4 N: t5 D
  4. 0 U  w9 c1 t; u% u6 G
  5. class Quest (JQuest):+ J" D# w1 p! Z$ f+ y+ W) ]  Z
  6.   def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)3 W4 P; ]! X2 h
  7.   def onEvent (self,event,st):+ k  X/ d! w. B: [& E2 \2 E
  8. id = st.getState()
    2 ]. e' r) ^4 B+ h. z/ Y
  9. if   id == CREATED  : st.setState(STARTED)5 l/ K) V* W# ?
  10. elif id == COMPLETED: pass: N* j# Q( S" V9 T
  11. elif id == STARTED  : check(st)
    1 T7 [% |4 a* Q4 P! Q
  12. return
    6 b$ M) t" P% v5 Y& [

  13. * D1 W+ B$ d5 n1 a5 {# l- N& h% p: L& i
  14. QUEST     = Quest(201,"Tutorial", "Tutorial quest")9 P, F$ G$ e  b
  15. CREATED   = State('Start',     QUEST)
    + k1 C. y4 @' N! v, ^4 h& E
  16. STARTED   = State('Started',   QUEST)
    ! b' q9 a5 @, G; M; p
  17. COMPLETED = State('Completed', QUEST)+ `% L+ y7 K5 Z

  18. : v2 k* T# B5 f2 I" b
  19. QUEST.setInitialState(CREATED)
    5 k4 p! p- l- f/ u; r
  20. QUEST.addStartNpc(7056)
    . s* z6 Y& n9 X/ ]  l
  21. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Теперь рассмотрим, как это работает.* X6 B6 a" e- m; T! D7 l
Игрок подходит к начальному NCP (в данном случае 7056), нажимает на «Quest». Квест будет создан и состояние квеста перейдет к CREATED и игроку будет показана страничка Start.htm с описанием квеста. Тогда метод onEvent, поле открытия странички Start.htm переведет состояние квеста в STARTED и игроку будет показана страничка Started.htm, где будет опсание того, как найти keltirs и .т.д.
8 K! _3 ~" R+ K' D& v: T( S+ `$ N& J9 b+ l/ Y3 F% n
) }9 t5 Y6 S" ~- f, Y
При состоянии STARTED будет зарегистрирован дроп «fangs» при убийстве keltirs. Игрок может вернуться к стартовому NCP и спросить о квесте – метод onEvent будет вызван снова. Если у игрока не хватает необходимого количества предметов, то метод check() не переведет квест в следующее состояние и Started.htm будет показана снова. Но если игрок собрал необходимее количество предметов (в данном случае 4 клыка), то метод check() вызовет метод completed() который переведет квест в новое состояние COMPLETED, заберет все клыки, даст карту мира, т.к. это награда за квест, покажет Completed.htm и завершит квест.% t  |% a0 i9 G, Z( K/ l4 g: O% m( W
# ^( T' y7 ?" `0 ^& v4 W6 B
) r( m' h: e1 I' A! q# V
Теперь давайте сделаем наш квест более похожим на то, что он должен из себя представлять.
+ V7 q4 L! ]  j" wПрежде всего у нас есть 3 метода для объявления их в Яве – onTalk, onKill и onEvent. Если методы onTalk и onKill не объявлены, то за них все будет делать метод onEvent, т.е. определять квестовых монстров и вызывать диалоги NCP. Есть примечание, методы onTalk и onKill будут вызывать только диалоги с NCP в зависимости от текущего состояния квеста. Метод onKill будет вызываться только тогда, когда мы убиваем квестового монстра.; _6 w9 K7 L) ]9 {

+ q4 R' }% z1 o# i0 `

( ^/ L" W# H  l+ K* wДавайте рассмотрим как вызывается метод onKill при убийстве keltir в состоянии квеста STARTED:
. h1 ~- W$ o. I+ v6 f; W
  1. STARTED.addKillId(KELTIR_NPC_ID)
Скопировать код
и метод onKill в классе Quest:
$ O  T# H$ n7 l% n1 x- w- X3 h8 x
  1. class Quest (JQuest):2 e, t; G9 {) Y. S( z" I# D
  2.   ...
    ! Y/ _; v0 m7 |& M$ B
  3.   def onKill (self,npcId,st):0 |% U+ e" w6 O4 O1 D9 N& A$ H
  4. if npcId == KELTIR_NPC_ID:
    * B/ ?8 S- D& y( o, Q
  5.    n = getCount(st)0 \8 _. n$ j% e- G% s( q9 z. C
  6.    if   n == 0:
    / \  u. U' T. L3 z; F3 r* T
  7.        return "Chat0.htm"7 N: Y, f9 j2 Z* k, p5 X
  8.    elif n == 1:- T5 K0 b# V5 W5 s) J, X
  9.        return "Chat1.htm"( v7 \7 |% T7 m6 b1 c! [2 r( k
  10.    elif n >= 4:2 V) V- T9 [2 E
  11.        return "Chat4.htm": G5 n7 g. N* j* {/ \, s8 k
  12.    return "Collected "+str(n)+" of 4 fangs"
    4 o/ G: e: y3 t
  13. return
Скопировать код
Метод onKill (а так же метод onTalk) имеет следующие параметры:( o3 X3 t6 R. w8 G

2 R4 h+ V  ?8 p) D. y6 l. A
2 `! O3 u0 ?' m5 V1 \
• self – квест
. L& D+ ]0 J: P# c+ `• npcId – ID NCP, которого мы должны убивать (если это метод onTalk, то ID того NCP, с которым мы должны поговорить)./ v5 {6 q0 n2 f2 _+ z/ n/ ?
• st – текущее состояние игрока.4 s8 }$ b9 i3 D6 v, [

; s3 r) `' s# D& k/ Y# g! L

: I; g  {  g. `: NВ этом методе мы проверяем и отмечаем, является ли убитый NCP keltir’ом. В основном эта проверка не нужна, т.к. у нас только KELTIR_NPC_ID.
- l/ V; h/ M  q" U: L8 `$ `2 {' q& {) B0 T3 |; i0 O

" F* K: {  h! x* ~% kЗатем проверяем количество предметов (в данном случае количество клыков), и если их вообще нет, то возвращаем строку "Chat0.htm", если только один предмет, то возвращаем строку "Chat1.htm", если же предметов 4 или больше, то "Chat4.htm". Если строка возвращена из методов onEvent, onKill или onTalk, то сервер покажет соответствующие htm. В Chat0.htm может иметь следующий текст: «Вы не имеете ни одного клыка, возвращайтесь позже, когда соберете 4 штуки и бла, бла, бла…», в Chat1.htm может быть следующий текст: «У Вас всего 1 клык, по этому соберите еще…». В Chat4.htm – «Вы собрали необходимое количество предметов, возвращайтесь к вашему тренеру, что бы завершить квест…»& }; m- O1 X6 Q. B- o# b5 P
* l8 A- `3 G6 m/ I

( ^" ?' B( P7 E7 n4 C% AПримечание: если в строка return начинается с "<html>", то будет показана страничка html с текстом, который стоит далее. Так вместо:
) q& v$ e# Y, d5 p8 Oreturn "Chat4.htm"
1 s* M# E9 F1 @- {0 d* b( f, Y$ n2 C
/ X( n; M3 J7 M& D/ s% p8 e
1 d* k, w8 V( u( ~9 L4 T1 b5 H1 n- h
можно поставить:: B/ i- a" ], p5 `' ?9 n5 N
  1. return "<html><body>Return to your trainer to complete the quest</body></html>"
Скопировать код
Так же если строка заканчивается без .htm или в начале нет <html>, то текст будет выведен, как системное сообщение в окне чата. В нашем случае мы сделаем так, что бы при каждом убийстве keltik выводилось системное сообщение: «Собрано N из 4-х клыков».
: R, ]: |4 t+ i7 S) e* A  F+ K. \9 `/ g/ B8 w3 t+ v/ ?
8 ?+ T' e( ]# A: w8 ]0 Y0 r
Наш код для onKill имеет один недостаток. Он будет постоянно показывать Chat0.htm, Chat1.htm и Chat4.htm, нам же необходимо, что бы Chat0.htm и Chat1.htm показывались только один раз. Как нам это сделать? С помощью переменных.! P  I& C; c$ j' I* B$ h
/ T0 ?0 Q) `* ?  O
6 h! R5 l: ]5 G0 [( c+ N
В каждом квесте строки могут храниться с помощью переменных. Эти переменные сохраняются в Вашей БД. В каждом методе мы можем назначить, прочитать и удалить переменные. Давайте изменим метод onKill, так что бы каждый диалог вызывался только один раз.& K. C4 c4 e' R0 [! a& l5 ]; B# N# l
  1. def onKill (self,npcId,st):% N0 J! o% l* g3 H4 _7 J4 R* K( u
  2. if npcId == KELTIR_NPC_ID:* n" _  Z5 A7 u8 d6 Q4 U1 U
  3. n = getCount(st)
    ! N( N5 I9 Q+ ?# e, f
  4. if n == 0:
    # y- w' y! I0 M* A
  5. if st.get('chat0') == None :
    2 w; {! |- t7 x+ Q) U  K
  6. st.set("chat0", "true")# \# \* W: w' l* `8 g
  7. return "Chat0.htm"
    0 }: p8 |) _$ J9 D9 R8 U
  8. elif n == 1:( H7 ^! x& k1 |& V
  9. if st.get('chat1') == None :, q( w& n$ k! X* `& W
  10. st.set("chat1", "true")9 |6 ^6 A/ B# R' C
  11. return "Chat1.htm"
    : |0 Z! a( P) P& R$ {1 X/ Z- ]
  12. elif n >= 4:# O* H; I  s4 f' h
  13. return "Chat4.htm", O3 \9 [5 y9 S: |3 M' e
  14. return "Collected "+str(n)+" of 4 fangs"
    5 |- P, \7 R0 [' @' i1 N
  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.2 L6 o! s5 G  r8 e2 `: C# m9 Y* n

+ z6 V' ]+ T5 h6 h
0 s( U3 P& S2 R" X( k: |
Вот конечный рабочий вариант квеста:& K7 _; m! ]1 X# v% E* Z* E# s
  1. import sys
    . }# Y- [$ p+ `3 \# X' Y% M4 C
  2. from net.sf.l2j.gameserver.model.quest import State# O* m3 C7 C8 W, j2 ~2 W0 o7 i$ K
  3. from net.sf.l2j.gameserver.model.quest import QuestState
    * p6 H8 e7 V& O+ u  x! v
  4. from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest
    $ b6 `% F- V4 e; i$ q7 A- K" V: s
  5. 6 Z% z2 p+ ]# v+ K
  6. KELTIR_NPC_ID = 12082; `  b% z' [" a# r- c0 l
  7. FANGS_ITEM_ID = 1859
    6 d, L! a9 z# I6 F
  8. DROP_RATE    = 500000
    8 F) D' t" U2 S( }$ z  X9 r& f

  9. 0 o5 ]7 `3 A' T* N
  10. WORLD_MAP_ITEM_ID = 1665( Z6 v! Z) `/ K3 D& G

  11. # ?- Z" d+ r$ \& W
  12. def getCount(st) :
    ' s- n  _6 z. M
  13. return st.getQuestItemsCount(FANGS_ITEM_ID)" d6 J" B) H" ?

  14. 6 X: r* J$ @7 o- i; f2 `+ U
  15. def completed(st) :
    1 {9 M1 i, t) ]" [- Q4 ~( `
  16. st.setState(COMPLETED)  R# b9 v$ e8 t/ S5 o/ P+ n/ _4 [
  17. st.clearQuestDrops()3 J$ }" B. n; w. M
  18. st.takeItems(FANGS_ITEM_ID,-1)
    ; `+ o/ T  F, r
  19. st.giveItems(WORLD_MAP_ITEM_ID,1)
    + A" Q1 D. L/ z4 u, V) N, L
  20. st.exitQuest(False)
    " w; @. C" |+ B4 _3 ]  u: p
  21. return' g5 R+ X0 g6 `) m1 ~5 r
  22. / ?5 [" U7 O' M+ t
  23. def check(st) :8 Z" L8 m3 }& Y- {% w1 L
  24. if getCount(st) >= 4 :
    ! s* t5 G2 B& j, Q7 ~- z8 w
  25. completed(st)
    & d* u# W4 D: Q4 t1 t
  26. return- e5 X' m8 ^3 P4 P2 X3 N8 L2 \

  27. " d4 h' W, E2 i4 m5 C
  28. class Quest (JQuest):
    : Z# ], N; f% |; `( K& e

  29. . s5 d- t  V8 b# T
  30. def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr). x3 z1 _( W' ]& f  x+ h. `) r

  31. , h( n: R5 E# v7 l9 Z5 J8 r' q# [
  32. def onEvent (self,event,st):# ^/ }, Z. ]" ^
  33. id = st.getState()
    + V1 [; ^, ?  l5 x# M
  34. if id == CREATED : st.setState(STARTED)$ d- n: A. Q8 A' h
  35. elif id == COMPLETED: pass
    " z+ g2 J; B/ g6 c( Q) `3 [2 H; ~
  36. elif id == STARTED : check(st)- P4 j( y( v! g1 w; x* Z
  37. return7 O% d6 q9 V- v: w# \

  38. & w4 B9 T+ r# O+ U6 W! B
  39. def onKill (self,npcId,st):
    + g+ G+ o5 L# s. R# N7 \* e
  40. if npcId == KELTIR_NPC_ID:; r- a; I' N, k; \/ L4 {: F
  41. n = getCount(st)
    " T1 L1 G9 k/ W+ \& ?, U9 k
  42. if n == 0:
    1 A; r0 B' h! o5 e* f
  43. if st.get('chat0') == None :- t- M' r; d( s  N+ n
  44. st.set("chat0", "true")$ H( S- ]$ L! m8 ?* x
  45. return "Chat0.htm"3 q) @) h" j4 l. z! T! w$ _6 h
  46. elif n == 1:; i! h5 e, j/ A
  47. if st.get('chat1') == None :
    . N3 |* c6 [7 s$ s7 m+ o7 E1 I" E
  48. st.set("chat1", "true")
    4 b/ N" n: v* s6 Z: M
  49. return "Chat1.htm"
    $ ]# K8 y, ^. y2 p
  50. elif n >= 4:  w. T' \6 J2 @3 K6 M* U* q6 Z# K
  51. return "Chat4.htm"
    ! m& O7 s$ _1 O% P1 |. P  h
  52. return "Collect "+str(n)+" of 4 fangs"+ E( Q+ ?4 V9 X) ?7 U9 X( n! p
  53. return
    0 H. e) H) |6 W2 Y; z1 I

  54. " C+ ?- v9 }: W2 e' j
  55. QUEST    = Quest(201, "Tutorial", "Tutorial quest")( x" |( S7 q1 L5 O# e7 K$ e
  56. CREATED = State('Start',    QUEST)# p' Q. f( @; l7 k
  57. STARTED = State('Started', QUEST)! P9 B  I& ^$ N
  58. COMPLETED = State('Completed', QUEST)# _, X6 `, D7 M

  59. ' w" c' {! G2 r+ x
  60. QUEST.setInitialState(CREATED)
    : P3 h6 m: ^  ~
  61. QUEST.addStartNpc(7056)
    . U% M9 L0 a$ H8 {3 H4 H% e
  62. QUEST.addStartNpc(7012)/ U8 w) O3 V9 P+ f3 C/ s
  63. QUEST.addStartNpc(7009)0 v1 W# Y6 \: k- H+ V
  64. QUEST.addStartNpc(7011)
    2 R. S9 X( s1 v2 S7 n! C
  65. . o) _3 n) w/ e1 G# h0 G
  66. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
    ! S, F9 Z$ q- g8 `& ^
  67. STARTED.addKillId(KELTIR_NPC_ID)
    / W& Z. U. h) R& t7 M
  68. STARTED.addTalkId(7056)
    : `* n* O* w9 l7 U
  69. STARTED.addTalkI d(7012)
    $ b& r8 z+ h" h3 O& z
  70. STARTED.addTalkId(7009)
    : p' y" {8 A; b8 S% l  |7 A2 Y/ L
  71. STARTED.addTalkId(7011)
Скопировать код
, ?+ D9 a3 s: I$ @( E! `& w6 _$ G
* J$ i' k6 S( h" n$ M. L





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