Top.Mail.Ru

[Квесты] Создаём собственные квесты (часть 2)

[Скопировать ссылку]
admin Опубликовано 2024-9-17 19:36:47 | Показать все сообщения |Режим чтения Распечатать Назад Вперед

Зарегистрируйтесь сейчас чтобы найти еще больше друзей, и получить полноценный доступ ко всем функциям сайта!

Для просмотра Вам необходимо авторизоваться Если Вы еще не зарегистрированы, перейдите по ссылке:Зарегистрироваться

x
Хроники        Interlude
: F+ Q+ P/ C- B) QСборка        L2j
/ r, i" L  ^4 w1 s5 X) f1 AОбратите внимание: в файле htm стартового NCP обязательно должна быть ссылка на квест:
4 `, y- E, S: {1 c- T. d1 L( t
  1. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста:
9 \4 b- i/ B& _/ c6 R
4 e. I8 U; ~4 f# j" ~; V) B) [$ w
  1. if getCount(st) >= 4 :
    / G4 f2 L( {$ b0 D* u0 g
  2. completed(st)' Z/ ]. {  H/ m2 v
  3.   return5 \. z4 Y0 a' a9 x2 q! @

  4. % N5 U( [8 W% N- ?. S. t" s" N9 {2 Y
  5. class Quest (JQuest):) q- g/ Y# H- w6 d* ]
  6.   def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)
    9 R4 i6 j- Y, k, \0 F9 M% Q
  7.   def onEvent (self,event,st):* K2 A# {. M& X- I) \3 k- [* q
  8. id = st.getState()
    ( {: K  s. s. b- F
  9. if   id == CREATED  : st.setState(STARTED)
    5 o5 u7 T" z8 V' @+ x: v
  10. elif id == COMPLETED: pass
    5 @- i1 J, a! {& C
  11. elif id == STARTED  : check(st): y- ^1 L# a7 f- i! w* }; M
  12. return/ s- ?! ?1 L5 v8 L- c3 c$ q& E
  13. % e# x) C1 R3 e4 }9 g5 T7 i
  14. QUEST     = Quest(201,"Tutorial", "Tutorial quest")( G  m9 c& m, h/ F7 Q/ H) O
  15. CREATED   = State('Start',     QUEST)
    $ }% ~. ?- H7 z- O3 p) n/ G# f
  16. STARTED   = State('Started',   QUEST)  F& k& L3 X& }$ i
  17. COMPLETED = State('Completed', QUEST)
      t# `8 K6 n2 z6 o! L" z
  18. - K* {5 n( f0 B1 k) \  a  g
  19. QUEST.setInitialState(CREATED): i. K, e% _5 b3 z' I0 I4 N7 D" V7 T  j
  20. QUEST.addStartNpc(7056), C  O  x, w  X5 _0 g5 s- W
  21. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Теперь рассмотрим, как это работает.
% M9 Y) F- z) N" j( f/ ]Игрок подходит к начальному NCP (в данном случае 7056), нажимает на «Quest». Квест будет создан и состояние квеста перейдет к CREATED и игроку будет показана страничка Start.htm с описанием квеста. Тогда метод onEvent, поле открытия странички Start.htm переведет состояние квеста в STARTED и игроку будет показана страничка Started.htm, где будет опсание того, как найти keltirs и .т.д.
0 n. R# K9 `: N, Z! a
2 s& a( @4 A6 ~9 s, g% [, O$ i8 X

( s( G3 m# ]- ^) m4 }; z' UПри состоянии STARTED будет зарегистрирован дроп «fangs» при убийстве keltirs. Игрок может вернуться к стартовому NCP и спросить о квесте – метод onEvent будет вызван снова. Если у игрока не хватает необходимого количества предметов, то метод check() не переведет квест в следующее состояние и Started.htm будет показана снова. Но если игрок собрал необходимее количество предметов (в данном случае 4 клыка), то метод check() вызовет метод completed() который переведет квест в новое состояние COMPLETED, заберет все клыки, даст карту мира, т.к. это награда за квест, покажет Completed.htm и завершит квест.5 u4 [  V) [0 L

, w. V/ r6 m4 e  y1 e. Z  w

& W3 u8 v" o$ o; @" p, G. \8 B; QТеперь давайте сделаем наш квест более похожим на то, что он должен из себя представлять.
8 D6 Y2 Z, b. o0 [, v6 O" ~, M$ IПрежде всего у нас есть 3 метода для объявления их в Яве – onTalk, onKill и onEvent. Если методы onTalk и onKill не объявлены, то за них все будет делать метод onEvent, т.е. определять квестовых монстров и вызывать диалоги NCP. Есть примечание, методы onTalk и onKill будут вызывать только диалоги с NCP в зависимости от текущего состояния квеста. Метод onKill будет вызываться только тогда, когда мы убиваем квестового монстра.$ c( C" U0 Q' h& h6 ?, T, T3 R
+ l% e" n+ x, f8 L- F8 |1 m9 M9 u4 w4 {

/ m+ ?" i7 u6 Z, W. XДавайте рассмотрим как вызывается метод onKill при убийстве keltir в состоянии квеста STARTED:9 D; u4 \8 u- J& b& m3 |
  1. STARTED.addKillId(KELTIR_NPC_ID)
Скопировать код
и метод onKill в классе Quest:) Y* {4 R7 z# M: K

  }: `7 S( B! u
  1. class Quest (JQuest):
    1 D5 m9 {5 T6 h* h1 h; v
  2.   ...
    ; V$ s+ P! l/ W% e9 Q6 ?
  3.   def onKill (self,npcId,st):4 U/ w4 E5 e6 a7 Z+ R# X: u
  4. if npcId == KELTIR_NPC_ID:$ `. `  T+ X8 D6 Z2 P
  5.    n = getCount(st)
    * t! S1 p5 o- g2 }
  6.    if   n == 0:
    2 |) k  A9 i( i' }
  7.        return "Chat0.htm"
    ! s; {& p4 I8 `2 G2 T
  8.    elif n == 1:
    ' Y1 Y& K3 {" w7 W: H. P3 E
  9.        return "Chat1.htm"
    ' o7 n  F: ^. A& G* L8 {! |" i
  10.    elif n >= 4:9 Z2 F3 R) W! B; V
  11.        return "Chat4.htm"3 a; f7 E6 i; Q$ z
  12.    return "Collected "+str(n)+" of 4 fangs"
    8 B) b4 H" @; m3 F# `& C% i5 V: _
  13. return
Скопировать код
Метод onKill (а так же метод onTalk) имеет следующие параметры:9 F2 ]+ S' x  v
, }. ?. N- i9 z9 L- M6 s! G- ]
6 e# d1 t" K: ]& h5 S8 ~& v
• self – квест
" x/ Q7 O$ \$ J• npcId – ID NCP, которого мы должны убивать (если это метод onTalk, то ID того NCP, с которым мы должны поговорить).) Z, w& z# h6 {) P' A0 B
• st – текущее состояние игрока.' W- f0 E0 Q% j0 ?( O# o
, k7 [4 [2 S2 `( o1 o2 N
) Z6 ~7 q  C' O5 M+ u' u
В этом методе мы проверяем и отмечаем, является ли убитый NCP keltir’ом. В основном эта проверка не нужна, т.к. у нас только KELTIR_NPC_ID.. y) z- J2 z8 P7 d8 q9 Z
4 Y& e8 S: |; t4 ]. C. s4 e% C! F
) Z0 f& `: I7 p% Q: i/ {1 H* o2 {# s, \
Затем проверяем количество предметов (в данном случае количество клыков), и если их вообще нет, то возвращаем строку "Chat0.htm", если только один предмет, то возвращаем строку "Chat1.htm", если же предметов 4 или больше, то "Chat4.htm". Если строка возвращена из методов onEvent, onKill или onTalk, то сервер покажет соответствующие htm. В Chat0.htm может иметь следующий текст: «Вы не имеете ни одного клыка, возвращайтесь позже, когда соберете 4 штуки и бла, бла, бла…», в Chat1.htm может быть следующий текст: «У Вас всего 1 клык, по этому соберите еще…». В Chat4.htm – «Вы собрали необходимое количество предметов, возвращайтесь к вашему тренеру, что бы завершить квест…»9 w3 l7 i% Q+ j' o/ R$ C# y

; Y: D: L$ _5 Y: b

0 B3 @( ~* r( I# b2 ^, vПримечание: если в строка return начинается с "<html>", то будет показана страничка html с текстом, который стоит далее. Так вместо:
  S' Q  p( L) L7 W1 p. {9 j1 k3 Lreturn "Chat4.htm"
" L7 J$ ?' w& f0 }8 a8 B0 b2 f1 \) Y6 h0 W4 B5 _

; C9 j, H4 ?3 s3 P; J8 E& c+ Oможно поставить:
/ D6 e/ v2 @8 l- B7 S. u2 m
  1. return "<html><body>Return to your trainer to complete the quest</body></html>"
Скопировать код
Так же если строка заканчивается без .htm или в начале нет <html>, то текст будет выведен, как системное сообщение в окне чата. В нашем случае мы сделаем так, что бы при каждом убийстве keltik выводилось системное сообщение: «Собрано N из 4-х клыков».
4 V* \2 T' D) N0 ^/ O) }5 h4 D- D3 C; e$ |- h

4 b' J+ \4 r$ ]5 m: h; R2 [4 l$ WНаш код для onKill имеет один недостаток. Он будет постоянно показывать Chat0.htm, Chat1.htm и Chat4.htm, нам же необходимо, что бы Chat0.htm и Chat1.htm показывались только один раз. Как нам это сделать? С помощью переменных.
2 f; t: C& r7 g$ l5 G: i5 V3 ]2 c, b" p' q! r8 N  N
/ A5 Q( Z/ m* d3 _7 c- Q
В каждом квесте строки могут храниться с помощью переменных. Эти переменные сохраняются в Вашей БД. В каждом методе мы можем назначить, прочитать и удалить переменные. Давайте изменим метод onKill, так что бы каждый диалог вызывался только один раз.7 q+ A3 V, D# R- \  G4 \
  1. def onKill (self,npcId,st):
    + q$ W" r0 z! Y
  2. if npcId == KELTIR_NPC_ID:
    1 r$ _' J5 I3 g8 u( H
  3. n = getCount(st)
    ! E( M) z2 T: G2 a3 F! q2 v
  4. if n == 0:
    1 T5 V* N. L  H# p
  5. if st.get('chat0') == None :0 c2 u* r* ?; ?  [2 d9 J
  6. st.set("chat0", "true")
    5 h( E0 F+ B3 i8 D. `
  7. return "Chat0.htm"
    . Y  y2 j- {, v+ X* }
  8. elif n == 1:" \6 j7 Z7 x3 x7 v
  9. if st.get('chat1') == None :
    ! ~' z+ O0 I6 \+ F4 c
  10. st.set("chat1", "true")$ Q0 Y! j" u2 ]& X" ]$ d: H
  11. return "Chat1.htm"
    4 z' p/ [1 |- o2 k. e0 Y
  12. elif n >= 4:8 f9 ^. V6 [8 ?( Q$ |" M: P2 p
  13. return "Chat4.htm"7 r3 b( R# F0 e1 T) t/ \3 j" n! ~
  14. return "Collected "+str(n)+" of 4 fangs"6 S  I" g. B* ]1 O5 ^! I5 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.
* W. `8 T3 o0 H: E' \2 L3 a" k' V0 B3 k  Y5 r

) V7 f# O8 P" F+ SВот конечный рабочий вариант квеста:
- o2 r% i/ O! p8 M* c0 `+ L
  1. import sys
    6 x* ]" m2 }; H( _6 X, {
  2. from net.sf.l2j.gameserver.model.quest import State+ k4 L# G( t$ p6 |' E; Z
  3. from net.sf.l2j.gameserver.model.quest import QuestState, w7 c) L) Z' W' y/ V7 a7 H! y+ v% Q
  4. from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest
    : {: ]& ^$ l2 D# l4 C; f

  5. 3 M) t+ a1 j. K+ G
  6. KELTIR_NPC_ID = 120825 Q; J- f' M! Y/ X) A. R9 ]: s
  7. FANGS_ITEM_ID = 1859
    ( u* H1 f: d9 H# Z/ \- h
  8. DROP_RATE    = 500000) ^: _7 o) R0 k! }

  9. ; z! b3 B' @8 Z1 h7 o. Z
  10. WORLD_MAP_ITEM_ID = 16656 Q3 E& O& z9 j- S- q1 v

  11. : ~- M) W) Q8 F) s' ~6 H& l0 v
  12. def getCount(st) :
    : {) y0 n% f7 F+ Z& F1 ?  n
  13. return st.getQuestItemsCount(FANGS_ITEM_ID)$ t2 H, H. b! r
  14. 6 y  P" }: j3 S, S
  15. def completed(st) :
    ' U$ v" o! u- Q3 S5 L' ?; ]- D
  16. st.setState(COMPLETED)
    - R* ?  T: W# E' L0 O$ r/ J
  17. st.clearQuestDrops()
    ! d8 w) q6 S- h
  18. st.takeItems(FANGS_ITEM_ID,-1)* n+ P" }% I* h9 c- {
  19. st.giveItems(WORLD_MAP_ITEM_ID,1)# u7 ]/ l9 G+ N: L5 h
  20. st.exitQuest(False)! B) C6 I: f( c
  21. return9 j+ Y8 \- w) e# L: r3 ?

  22. 9 g$ {: }% w( `% d+ i
  23. def check(st) :
    0 |) `/ _+ g& x# d. Y
  24. if getCount(st) >= 4 :
    ! T/ d3 X8 _4 d/ _
  25. completed(st)3 Y+ L( W) `! o; C! O, P$ B
  26. return& n3 t' j: Z; U2 s3 @6 S

  27. ( L; M: x* G# S: q$ v
  28. class Quest (JQuest):) z5 v6 ^7 L+ R! v) t. t  C  O
  29. / D: X6 V2 N2 \1 y6 Q. A
  30. def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)1 t. s6 m$ C, a! C: t% T4 _

  31. / q9 m1 y, _4 U7 p
  32. def onEvent (self,event,st):
    : ~7 ^/ g- j0 g2 W* ~  ^
  33. id = st.getState()0 x3 z' ^) n) t6 H, z8 ?
  34. if id == CREATED : st.setState(STARTED)
    3 {. |+ j7 U! ^9 Y
  35. elif id == COMPLETED: pass7 g- ~. h: V: e. ^5 _& z0 s! p3 J* f
  36. elif id == STARTED : check(st)/ \! B5 e( ~0 D: J% `; {
  37. return
    % J# @* b/ |$ a6 `+ x- `  F
  38. % ^1 N5 u4 l  N2 ~; b
  39. def onKill (self,npcId,st):
    ! f- Z- R1 ^6 V
  40. if npcId == KELTIR_NPC_ID:; O+ P' Q: N+ y# b/ f
  41. n = getCount(st)4 w( S% U1 N! S! R0 Y
  42. if n == 0:3 M3 ?3 ^7 C2 S9 U: y
  43. if st.get('chat0') == None :+ @) n7 y$ m! T; U9 u4 ^
  44. st.set("chat0", "true")- e% n$ H9 q; o% \
  45. return "Chat0.htm"- Y" Z6 g( X3 j/ \% E1 M
  46. elif n == 1:$ u0 c; `+ G5 D: j& ?; ~4 u
  47. if st.get('chat1') == None :  ^; y* T* @9 C& S* q
  48. st.set("chat1", "true")
    . K6 |7 q& O7 m; W3 i7 A5 x
  49. return "Chat1.htm"
    ( ]! n& ?: k. X  R) f2 ~! P2 Q
  50. elif n >= 4:, B8 Z' g& l1 M9 |3 R* b, b5 t# z" d
  51. return "Chat4.htm"; n% w0 t) \0 o
  52. return "Collect "+str(n)+" of 4 fangs"+ v, L! n( \* I; ~
  53. return
    2 [* e- o2 P) A$ F7 N3 u

  54. $ z* B* R# B" n3 j9 @
  55. QUEST    = Quest(201, "Tutorial", "Tutorial quest")
    , y) K' p' x2 d* h. ~" L
  56. CREATED = State('Start',    QUEST)
    + `, n* W/ A; X' d$ q2 N( H, {* y* L
  57. STARTED = State('Started', QUEST)+ I7 Q+ S3 R  _7 d
  58. COMPLETED = State('Completed', QUEST)
    6 ]) q. f1 }# b: H6 O
  59. ( u; m3 O2 d+ I
  60. QUEST.setInitialState(CREATED). ^( p+ `1 z7 K3 C5 q& k
  61. QUEST.addStartNpc(7056); G! x3 g) f. r: O7 O1 d+ F: P: _: T
  62. QUEST.addStartNpc(7012); [4 c& z2 }& E+ Y4 U) f2 M
  63. QUEST.addStartNpc(7009)
    + P3 r' v4 W3 o$ N6 H
  64. QUEST.addStartNpc(7011)% g! P) r0 w$ d; ^1 K+ B1 M

  65. ( W. [5 e6 B' P8 w
  66. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)7 g1 ?% o' H% a+ H! J; d) g
  67. STARTED.addKillId(KELTIR_NPC_ID)
    0 H! s) g, y3 ]9 D" T' C
  68. STARTED.addTalkId(7056)
    1 P) E* Z9 Q  e" o1 u
  69. STARTED.addTalkI d(7012)
    8 ]* R( G9 l# t* c+ g
  70. STARTED.addTalkId(7009)
    ' I: I) @! l1 x6 p3 L
  71. STARTED.addTalkId(7011)
Скопировать код

' d- \/ |0 {0 B- s, q3 {: C# |6 _/ U' a* u
Чтобы ответить, вам надо авторизироваться в системе Вход | Зарегистрироваться

Правил начисления баллов

Опубликовать
Сектор творческих людей
Горячая линия

638638758

С понедельника по воскресенье с 9:00 до 23:00

Обратной связь

admin@artace.ru Онлайн

QR-код

Powered by Discuz! X3.5© 2001-2021 Comsenz Inc.