Top.Mail.Ru

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

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

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

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

x
Хроники        Interlude
/ }  b$ t& Y- |5 pСборка        L2j( Y% E/ K, s: b; v, ?# _
Обратите внимание: в файле htm стартового NCP обязательно должна быть ссылка на квест:
0 P& Q7 v. p  d6 \) m
  1. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста:& l! w1 P  y5 i" v: `
/ ?  x; p+ G" J5 z' O
  1. if getCount(st) >= 4 :. R. c- A" T! v2 x5 V0 v* c. V! t
  2. completed(st): k# J# \3 f7 U$ y# ?/ N
  3.   return# H$ ?" Q4 a/ r6 B/ ^4 T, o# C) w8 u

  4. ! m; z- l/ ^/ _7 [% n4 e$ z( w4 k& Q
  5. class Quest (JQuest):
    - r6 L' E) y$ n0 o
  6.   def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr), D$ R0 c* j: A% m
  7.   def onEvent (self,event,st):
    # a. k7 B0 u# k( U' c7 k
  8. id = st.getState()
    , _$ F4 U* f0 g
  9. if   id == CREATED  : st.setState(STARTED)! S) n! z1 t7 c5 ]
  10. elif id == COMPLETED: pass9 W; Z# D: B. X1 m/ }
  11. elif id == STARTED  : check(st), N5 ^, @! ]# _- K  b1 j. K) Q
  12. return( M5 q' e) ~8 T' g

  13. 8 p& _& u/ k% l+ C# ^
  14. QUEST     = Quest(201,"Tutorial", "Tutorial quest")  S1 V( Z3 d2 l# P- h7 N! F" k
  15. CREATED   = State('Start',     QUEST)
    4 d2 H' o* H, V2 L
  16. STARTED   = State('Started',   QUEST)
    ; O4 `, T9 H6 Q% f/ o0 i+ L
  17. COMPLETED = State('Completed', QUEST)$ L; L3 y7 X! b, P
  18. , Z0 O& C  M0 }5 Y
  19. QUEST.setInitialState(CREATED)
    % O# M8 B! I; I* B, `
  20. QUEST.addStartNpc(7056)5 q# T3 Y( c5 _1 u7 ?% |
  21. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Теперь рассмотрим, как это работает.
. o  V: ^9 N# O2 ~6 iИгрок подходит к начальному NCP (в данном случае 7056), нажимает на «Quest». Квест будет создан и состояние квеста перейдет к CREATED и игроку будет показана страничка Start.htm с описанием квеста. Тогда метод onEvent, поле открытия странички Start.htm переведет состояние квеста в STARTED и игроку будет показана страничка Started.htm, где будет опсание того, как найти keltirs и .т.д.
( u: }# L# B0 _& s0 p3 Z) s4 U% i4 F* j- W5 {
, f1 |6 `: M4 {& Z- D
При состоянии STARTED будет зарегистрирован дроп «fangs» при убийстве keltirs. Игрок может вернуться к стартовому NCP и спросить о квесте – метод onEvent будет вызван снова. Если у игрока не хватает необходимого количества предметов, то метод check() не переведет квест в следующее состояние и Started.htm будет показана снова. Но если игрок собрал необходимее количество предметов (в данном случае 4 клыка), то метод check() вызовет метод completed() который переведет квест в новое состояние COMPLETED, заберет все клыки, даст карту мира, т.к. это награда за квест, покажет Completed.htm и завершит квест.
$ \& e3 T" W- v5 e
( @. u" W+ Y2 M! Z& M# R

1 V2 E8 \( I+ {" fТеперь давайте сделаем наш квест более похожим на то, что он должен из себя представлять.4 @; y* m  \" @2 \# B6 p. L
Прежде всего у нас есть 3 метода для объявления их в Яве – onTalk, onKill и onEvent. Если методы onTalk и onKill не объявлены, то за них все будет делать метод onEvent, т.е. определять квестовых монстров и вызывать диалоги NCP. Есть примечание, методы onTalk и onKill будут вызывать только диалоги с NCP в зависимости от текущего состояния квеста. Метод onKill будет вызываться только тогда, когда мы убиваем квестового монстра.8 N. @3 x# J0 K
. }$ v8 @0 D+ u0 H2 q8 _# y7 `5 {
( l, W: H) g2 j6 N8 f
Давайте рассмотрим как вызывается метод onKill при убийстве keltir в состоянии квеста STARTED:# G- m7 U9 V  m0 I. G
  1. STARTED.addKillId(KELTIR_NPC_ID)
Скопировать код
и метод onKill в классе Quest:
! v: r8 I$ B/ C" m. H! g
6 N$ b: Y. u* n6 _
  1. class Quest (JQuest):
    3 e/ g# _" T" s' u; G
  2.   ...
    . s; y/ [' g6 F. C' [( G/ B
  3.   def onKill (self,npcId,st):# O' v$ t# l" G5 {2 C
  4. if npcId == KELTIR_NPC_ID:5 g4 l% R% M" z* i: Y+ o
  5.    n = getCount(st)
    / H3 l, @: Y# A" ]+ M
  6.    if   n == 0:
    " ?' U, C5 p; D9 Y; |9 h
  7.        return "Chat0.htm"/ x( G5 ~  t) F0 S* v4 W  \  K% \- h
  8.    elif n == 1:
    2 b; G! O1 c+ m" G8 D; O
  9.        return "Chat1.htm"
    ; o) j+ b1 d6 P$ x9 N5 f. v! G
  10.    elif n >= 4:5 F/ \8 Z) {: g9 d# H% Y7 x7 g* ^" i% a
  11.        return "Chat4.htm"
    / Z9 F3 S  q: B5 F6 y
  12.    return "Collected "+str(n)+" of 4 fangs", k: J( n' m+ a% ?  S4 ?
  13. return
Скопировать код
Метод onKill (а так же метод onTalk) имеет следующие параметры:
# W# h0 m9 x0 B! }9 W7 l. H$ w0 b1 R7 ~6 }5 {$ [" ~

: p5 w5 y6 b% Q7 D% V• self – квест# Z' v7 l9 i) p& p
• npcId – ID NCP, которого мы должны убивать (если это метод onTalk, то ID того NCP, с которым мы должны поговорить).* F. [/ M! b; n( f' z
• st – текущее состояние игрока.
: [% f! [" u& n1 \- Q/ E- U7 \" g; O- O2 [
+ D7 C- I( N5 u( @
В этом методе мы проверяем и отмечаем, является ли убитый NCP keltir’ом. В основном эта проверка не нужна, т.к. у нас только KELTIR_NPC_ID.
( |  Y% d* \( ?& _1 [1 `& I1 @& P1 i
& B2 j7 Q1 f3 H2 z( \, E
Затем проверяем количество предметов (в данном случае количество клыков), и если их вообще нет, то возвращаем строку "Chat0.htm", если только один предмет, то возвращаем строку "Chat1.htm", если же предметов 4 или больше, то "Chat4.htm". Если строка возвращена из методов onEvent, onKill или onTalk, то сервер покажет соответствующие htm. В Chat0.htm может иметь следующий текст: «Вы не имеете ни одного клыка, возвращайтесь позже, когда соберете 4 штуки и бла, бла, бла…», в Chat1.htm может быть следующий текст: «У Вас всего 1 клык, по этому соберите еще…». В Chat4.htm – «Вы собрали необходимое количество предметов, возвращайтесь к вашему тренеру, что бы завершить квест…»
% c1 j: P; y3 V9 I( y
% L, _+ ?' E2 m
9 S, |2 `% t- W. p
Примечание: если в строка return начинается с "<html>", то будет показана страничка html с текстом, который стоит далее. Так вместо:- g$ U. P& q( p6 O  x# l# o
return "Chat4.htm"  q+ T# I4 a' a

  E( s/ V2 U6 J( u( c
3 t* V  P: e8 l9 o0 O& s$ C! ?
можно поставить:
5 B- A. [; W. [* l) g
  1. return "<html><body>Return to your trainer to complete the quest</body></html>"
Скопировать код
Так же если строка заканчивается без .htm или в начале нет <html>, то текст будет выведен, как системное сообщение в окне чата. В нашем случае мы сделаем так, что бы при каждом убийстве keltik выводилось системное сообщение: «Собрано N из 4-х клыков».9 K; ?" h6 D% s. D8 T+ F
9 L  W1 _6 n  l3 d* U

' \( f2 T$ _# l2 Q* H) P& I2 H% gНаш код для onKill имеет один недостаток. Он будет постоянно показывать Chat0.htm, Chat1.htm и Chat4.htm, нам же необходимо, что бы Chat0.htm и Chat1.htm показывались только один раз. Как нам это сделать? С помощью переменных.- r' A4 Y* V. H# a2 w
6 J; w  ~2 ]) X7 A: y

( Y: T. s& B( r. s) ?В каждом квесте строки могут храниться с помощью переменных. Эти переменные сохраняются в Вашей БД. В каждом методе мы можем назначить, прочитать и удалить переменные. Давайте изменим метод onKill, так что бы каждый диалог вызывался только один раз.
8 G# T% m' p! }$ A* V- g+ S
  1. def onKill (self,npcId,st):
    ( F' \! y6 R/ A" c8 e9 I
  2. if npcId == KELTIR_NPC_ID:. E' ~! u0 D" d6 r- P
  3. n = getCount(st)+ H; p  @4 {) o! P1 d
  4. if n == 0:
      b* H3 i9 C. Z4 U" [. L
  5. if st.get('chat0') == None :
    $ }+ z) A' R9 z4 B2 P! V
  6. st.set("chat0", "true"), f" }4 m+ ?0 f( ~6 ~
  7. return "Chat0.htm"8 _( _7 h5 h2 T3 x' G/ i9 b( q2 p
  8. elif n == 1:& L  e5 a1 z( \8 u5 O$ h2 ^* y2 e
  9. if st.get('chat1') == None :
    # R5 g5 J5 d  K( q# r4 u* _2 _
  10. st.set("chat1", "true")
    . {/ v* g4 d, y5 O9 m* \) O
  11. return "Chat1.htm"
    * n- J+ K- j5 H- ^' e
  12. elif n >= 4:+ k- \; t) V1 W7 U7 H( {
  13. return "Chat4.htm": U3 F" e9 s7 V, F! c% H  j
  14. return "Collected "+str(n)+" of 4 fangs"
    + u2 y' i: x& U! O) H2 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.- j0 _8 |. [3 I

. y6 M$ u. x) T- J7 v1 A( I8 a

! Q  Z% w0 R1 QВот конечный рабочий вариант квеста:$ {+ n2 L( L% }- D$ z
  1. import sys
    & p; s3 D8 X# G( Q9 X* S4 [4 Y3 U3 y
  2. from net.sf.l2j.gameserver.model.quest import State
    ( e! ]. e! j( z
  3. from net.sf.l2j.gameserver.model.quest import QuestState
    8 Q, C' J( V9 i1 C+ T, d, f& G2 S
  4. from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest
    $ j! Z+ {" j* d6 n5 ~

  5. % i1 c$ o) B2 K6 y- l' L3 a5 y
  6. KELTIR_NPC_ID = 12082: h. l5 p* L5 z/ Y& u
  7. FANGS_ITEM_ID = 18590 h" A2 `( }! r$ N0 u* L% V
  8. DROP_RATE    = 500000
    $ y3 W/ [7 H: J0 K) O

  9. - f" v, n( [+ }( i
  10. WORLD_MAP_ITEM_ID = 1665" d% S2 Y. }6 l3 u* c
  11. / s3 U9 e" H6 d5 D
  12. def getCount(st) :
    ! B$ L5 p! P3 i# x; D9 j
  13. return st.getQuestItemsCount(FANGS_ITEM_ID)
    ) h, ~* E7 L1 e/ H& x

  14. 6 e" Z( ^# ~9 W; ^, b8 s; @* o
  15. def completed(st) :1 J' h, f: J; W
  16. st.setState(COMPLETED)! p! A7 X" Y6 l$ ?  t
  17. st.clearQuestDrops()
    ) U# }+ f) a2 f( P1 ~
  18. st.takeItems(FANGS_ITEM_ID,-1)- f4 c2 z/ n( K9 N# J$ F9 N* [
  19. st.giveItems(WORLD_MAP_ITEM_ID,1)1 o$ T# J" d, R) N$ A. \1 c
  20. st.exitQuest(False)
    6 }3 L3 C" l) [2 C! H0 T8 V) b
  21. return
    0 S; c7 c4 ?* i$ {" h! R

  22. ' h  J, _# y( F: @" H" u" f, S( m8 J
  23. def check(st) :
    5 R& e, L, m1 ]- U
  24. if getCount(st) >= 4 :" x5 A( e! v  Z0 {+ P/ H7 ?
  25. completed(st)0 d2 b$ @, I! Y( y3 f& e( |1 r. S
  26. return
    ) [% j# {3 Q5 ]. o1 j

  27. 5 \4 A# C1 r5 x. J$ V
  28. class Quest (JQuest):
    3 b: _( J  d* ^) e& E

  29. / x; Z6 b8 G: u* k& ~# {/ j
  30. def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)2 |3 x' P! f; K  G- j. k
  31. ( o) ~2 q' |4 |4 k& u. o' I1 a8 w
  32. def onEvent (self,event,st):
    3 l1 B* S- i9 t/ [" E8 G# ~$ H
  33. id = st.getState()6 z# I0 e4 S2 S- |  V+ w4 Z
  34. if id == CREATED : st.setState(STARTED)
    8 r5 j4 Z9 H; d; v7 v/ q8 Q
  35. elif id == COMPLETED: pass
    ) G( H* x, }  l, {" e
  36. elif id == STARTED : check(st)
    ; j' {. o. Z5 P/ J2 \) S8 O
  37. return3 t# _( f, a0 }; ^. ~

  38. 1 z$ B2 E2 K/ D2 }
  39. def onKill (self,npcId,st):
    " m' F5 ]8 R; P6 [
  40. if npcId == KELTIR_NPC_ID:
    * \- a% w3 Q* D; M5 w2 C) r9 J# @4 `7 j
  41. n = getCount(st)
    ) T, C' R4 w! r& p6 \
  42. if n == 0:
    8 Z, N3 C4 j5 `( r! ?+ [
  43. if st.get('chat0') == None :
    8 ^0 Y* O5 D' M4 j; K( V9 d
  44. st.set("chat0", "true")
    & m3 b4 b" U" U+ v+ |$ B
  45. return "Chat0.htm"
    - w3 z8 s( |, H0 l
  46. elif n == 1:2 L0 _+ ~6 u: x
  47. if st.get('chat1') == None :* w, z8 ?/ h# n4 f0 s+ V8 o
  48. st.set("chat1", "true")$ W" W! M( ?( v! I- {  \
  49. return "Chat1.htm"
    % e2 h+ W, [4 [  V
  50. elif n >= 4:
    2 e/ @% Z) `  Z7 _/ q
  51. return "Chat4.htm"4 E$ c. p- I2 P9 s4 f4 |  ~
  52. return "Collect "+str(n)+" of 4 fangs"
    , d! A! z5 c" W; P" W
  53. return
    ( v. W& U8 L; K$ @' N
  54. 6 j$ e* `- G$ _( B  l! z! W0 s5 V4 E3 O
  55. QUEST    = Quest(201, "Tutorial", "Tutorial quest")
    7 n; c& D( Z0 ?% Z
  56. CREATED = State('Start',    QUEST)
    8 h& Q8 i8 l4 U
  57. STARTED = State('Started', QUEST)
    5 o/ i$ }# A! F, ~7 \4 o
  58. COMPLETED = State('Completed', QUEST)- o2 n8 l' y' p
  59. % ~4 W, Y2 q( K0 D" c
  60. QUEST.setInitialState(CREATED); F  A- _, r+ T3 _4 Z1 q. W+ m
  61. QUEST.addStartNpc(7056)
      |4 R. v3 A" q3 O- i! m2 l
  62. QUEST.addStartNpc(7012)
    ( ]* ~  @" h. b; s) t# {
  63. QUEST.addStartNpc(7009)
    $ x! z0 |- A; _
  64. QUEST.addStartNpc(7011)
    9 d. w7 F5 D- o- x% h7 h% u
  65. 1 }6 j5 q! _7 P8 p8 r% n$ g* D
  66. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)* h8 h9 x; q$ k1 V2 J
  67. STARTED.addKillId(KELTIR_NPC_ID)! x- H6 \5 y4 p9 v# W
  68. STARTED.addTalkId(7056)+ [& ]4 c) n" Z2 Z( `! y+ w, z! j
  69. STARTED.addTalkI d(7012)
    , W) e9 |! m6 g- q
  70. STARTED.addTalkId(7009)
    5 ~% ^; X2 t9 `( D) o, i. H
  71. STARTED.addTalkId(7011)
Скопировать код

9 V' h: A5 T( G* r5 e( W* [! K
1 M( I; q( }) d, ]6 f. _. e* f% M: A
Чтобы ответить, вам надо авторизироваться в системе Вход | Зарегистрироваться

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

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

638638758

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

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

admin@artace.ru Онлайн

QR-код

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