Top.Mail.Ru

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

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

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

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

x
Хроники        Interlude
. O, `, z4 L/ m) F7 w$ p6 I* R$ P& GСборка        L2j, [- A- e' n  D3 i; w0 H2 \, t: h
Обратите внимание: в файле htm стартового NCP обязательно должна быть ссылка на квест:
; c; S5 y9 ^4 c* W0 S1 W+ D
  1. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста:- U( ~( S6 K4 A: N, b7 z4 a3 }3 N
+ |3 s: _0 K; p; q+ Q9 |
  1. if getCount(st) >= 4 :/ J: E9 S+ i, R2 g5 h& f. S% ~
  2. completed(st)1 b, w& k( o" @+ v$ Z' T7 B
  3.   return& {- k" b) r; d! Q$ E4 U0 w, w" m7 h

  4. ) A$ P7 g# L4 Q5 O* l+ a2 t
  5. class Quest (JQuest):
    , q' {% |2 _$ I% F2 u# ~5 w  u8 x$ g
  6.   def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)* B0 z# ?- g- v% W: l0 O
  7.   def onEvent (self,event,st):2 {! p; C9 f6 g3 y
  8. id = st.getState()! {% N1 ~( k5 ]* q
  9. if   id == CREATED  : st.setState(STARTED)
    5 ?6 F# b+ A% {$ e
  10. elif id == COMPLETED: pass
    8 \. d# J. I" [( S" \. v
  11. elif id == STARTED  : check(st)
    , Y. M, T2 Q6 J1 F
  12. return! p  R& {2 Z# v. C3 P) ]
  13. 8 t4 j: {6 Z, t1 p* [. k/ V
  14. QUEST     = Quest(201,"Tutorial", "Tutorial quest")% y6 w. n; g! W0 u; Y
  15. CREATED   = State('Start',     QUEST)
      Z! O8 f; i# }8 j
  16. STARTED   = State('Started',   QUEST)$ E+ U5 _9 N; U  Y
  17. COMPLETED = State('Completed', QUEST)
    : `9 s- q0 Q: I7 v+ l
  18. 9 d; j1 Q; A+ r9 b6 w! I3 f  N6 T+ h4 o, O
  19. QUEST.setInitialState(CREATED)+ C" J; k5 V" r6 q2 R& N' F) l$ h
  20. QUEST.addStartNpc(7056)
    1 F, B/ Z- u/ R6 b* L
  21. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Теперь рассмотрим, как это работает.
! V# i1 l# E% O; }  AИгрок подходит к начальному NCP (в данном случае 7056), нажимает на «Quest». Квест будет создан и состояние квеста перейдет к CREATED и игроку будет показана страничка Start.htm с описанием квеста. Тогда метод onEvent, поле открытия странички Start.htm переведет состояние квеста в STARTED и игроку будет показана страничка Started.htm, где будет опсание того, как найти keltirs и .т.д.# O( g4 `, V) U7 u5 E

; Z) j6 s6 q) u2 X! J
' L1 V  D, {+ ?- `6 w; T
При состоянии STARTED будет зарегистрирован дроп «fangs» при убийстве keltirs. Игрок может вернуться к стартовому NCP и спросить о квесте – метод onEvent будет вызван снова. Если у игрока не хватает необходимого количества предметов, то метод check() не переведет квест в следующее состояние и Started.htm будет показана снова. Но если игрок собрал необходимее количество предметов (в данном случае 4 клыка), то метод check() вызовет метод completed() который переведет квест в новое состояние COMPLETED, заберет все клыки, даст карту мира, т.к. это награда за квест, покажет Completed.htm и завершит квест.
% e8 W. w6 X2 r7 _6 L2 }& B# O2 R( F2 u' Q
2 x2 q# X, ?" E% Z3 b+ I
Теперь давайте сделаем наш квест более похожим на то, что он должен из себя представлять.1 @0 d2 G8 S% R3 o+ M; I$ h
Прежде всего у нас есть 3 метода для объявления их в Яве – onTalk, onKill и onEvent. Если методы onTalk и onKill не объявлены, то за них все будет делать метод onEvent, т.е. определять квестовых монстров и вызывать диалоги NCP. Есть примечание, методы onTalk и onKill будут вызывать только диалоги с NCP в зависимости от текущего состояния квеста. Метод onKill будет вызываться только тогда, когда мы убиваем квестового монстра.
! o4 `4 x& m: ^4 I( J! {: B9 \! C, {# K* N3 y0 G  X/ G9 ?4 c) r
+ b$ n0 }0 {) R7 d1 D+ Q
Давайте рассмотрим как вызывается метод onKill при убийстве keltir в состоянии квеста STARTED:
9 S' _! O# v7 o4 l  \
  1. STARTED.addKillId(KELTIR_NPC_ID)
Скопировать код
и метод onKill в классе Quest:4 @  y( k0 \/ U8 |( U# Q( s! |. r

/ |1 N* R- V# s
  1. class Quest (JQuest):
    2 ^  q3 K6 d- i" ?1 m6 G
  2.   ...
    9 N2 a) W. c+ i/ z9 a; `+ \
  3.   def onKill (self,npcId,st):' V' i8 o1 N( s/ ]9 ?: T( u6 Y' w
  4. if npcId == KELTIR_NPC_ID:
    - I6 h! C' D0 z. A
  5.    n = getCount(st)
      `% Q! g; k0 }2 g% g
  6.    if   n == 0:
    # ~: w! ^% O( r5 D# z0 M& k9 j! t/ z
  7.        return "Chat0.htm"' c! D% n. b* ?6 p6 C; |) m# U' W
  8.    elif n == 1:
    ( G& F2 \2 V9 E5 e. p  W
  9.        return "Chat1.htm"
    - k" }  t5 D6 O$ k8 K6 V5 g
  10.    elif n >= 4:
    - N" C/ P1 v9 g5 q! O7 |# j- E
  11.        return "Chat4.htm"! D7 |. T% o# |+ q) s; k1 s
  12.    return "Collected "+str(n)+" of 4 fangs"
    4 d4 u. J, q$ }, Z
  13. return
Скопировать код
Метод onKill (а так же метод onTalk) имеет следующие параметры:
/ I. t7 V+ b9 c* Z; P" ^! s7 M; w" G! {; B1 O3 W1 T6 z: E

$ S% c' o/ A* p+ U* a% k) }% O• self – квест! n1 N/ u4 h0 {4 g) M7 r. E, \5 O
• npcId – ID NCP, которого мы должны убивать (если это метод onTalk, то ID того NCP, с которым мы должны поговорить).
, S& A& a" s3 @: Z. l• st – текущее состояние игрока.) E, J1 _9 ]1 R9 S; ]1 B5 a
9 r; g1 e; X4 {5 K
4 Y& n; D- C, s4 Q0 B
В этом методе мы проверяем и отмечаем, является ли убитый NCP keltir’ом. В основном эта проверка не нужна, т.к. у нас только KELTIR_NPC_ID.
: D5 C4 a: n4 w* O* @( s: B# I% G3 A

8 |$ t) f  z) g( ~% `1 SЗатем проверяем количество предметов (в данном случае количество клыков), и если их вообще нет, то возвращаем строку "Chat0.htm", если только один предмет, то возвращаем строку "Chat1.htm", если же предметов 4 или больше, то "Chat4.htm". Если строка возвращена из методов onEvent, onKill или onTalk, то сервер покажет соответствующие htm. В Chat0.htm может иметь следующий текст: «Вы не имеете ни одного клыка, возвращайтесь позже, когда соберете 4 штуки и бла, бла, бла…», в Chat1.htm может быть следующий текст: «У Вас всего 1 клык, по этому соберите еще…». В Chat4.htm – «Вы собрали необходимое количество предметов, возвращайтесь к вашему тренеру, что бы завершить квест…»
& G$ u/ P5 C! ?1 e' S5 r% i
1 ~% I2 S4 i2 r  P* y& L% G2 l
8 `' D2 B" N1 D/ T# p
Примечание: если в строка return начинается с "<html>", то будет показана страничка html с текстом, который стоит далее. Так вместо:: u+ o  z" ?! K6 E$ _9 j9 ~: x1 h  `- \
return "Chat4.htm"& u' s6 Z; y0 K- G! }, f! b
8 g, W: n' x3 @+ Z! K0 C* U

- w0 U+ g7 y" L" j" P: g3 zможно поставить:
/ O( \5 }) W) _  i3 p
  1. return "<html><body>Return to your trainer to complete the quest</body></html>"
Скопировать код
Так же если строка заканчивается без .htm или в начале нет <html>, то текст будет выведен, как системное сообщение в окне чата. В нашем случае мы сделаем так, что бы при каждом убийстве keltik выводилось системное сообщение: «Собрано N из 4-х клыков».
' s: O; E& q& C, {: y1 n7 p0 R( u5 d4 t; o/ X; a. P+ t+ q9 W
9 c& q7 \/ g. T1 s
Наш код для onKill имеет один недостаток. Он будет постоянно показывать Chat0.htm, Chat1.htm и Chat4.htm, нам же необходимо, что бы Chat0.htm и Chat1.htm показывались только один раз. Как нам это сделать? С помощью переменных.# b8 M1 ?2 B, r9 F) Q9 t. u& V- O
! m- w( }0 C7 ~+ D8 y/ D7 O

8 `4 V4 K9 s4 A9 @4 D# hВ каждом квесте строки могут храниться с помощью переменных. Эти переменные сохраняются в Вашей БД. В каждом методе мы можем назначить, прочитать и удалить переменные. Давайте изменим метод onKill, так что бы каждый диалог вызывался только один раз.  H* P2 ~2 k/ Z* C8 V
  1. def onKill (self,npcId,st):
    , L9 e: O# S/ C7 j  g0 O5 e8 [$ P
  2. if npcId == KELTIR_NPC_ID:1 u' @% w' l" i9 k
  3. n = getCount(st)7 G; c# Q8 A# }' c$ m, B
  4. if n == 0:
    , f+ j: N* U9 y# p4 E8 Z2 X
  5. if st.get('chat0') == None :# I5 q2 G1 z5 K- v0 i- q( R
  6. st.set("chat0", "true")4 \* k- {( Q/ l
  7. return "Chat0.htm"* n% M+ f* q1 g$ ]/ e7 F
  8. elif n == 1:* p$ i" K7 u6 R& H3 C
  9. if st.get('chat1') == None :
    * Y4 i/ G% \' P6 u( i( w! h& r
  10. st.set("chat1", "true")
    7 ]& M  W. }- d6 J1 z3 ]
  11. return "Chat1.htm"7 W# p6 [* c0 X7 R
  12. elif n >= 4:6 X1 r2 q3 Q5 U* r8 P
  13. return "Chat4.htm"& P2 I- L$ j; D, n/ K- E9 F5 p
  14. return "Collected "+str(n)+" of 4 fangs"
    ' p  R5 f8 H7 q& N3 S* b$ M
  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./ U# Y$ T/ w' F8 j2 z
7 o0 x! @6 R6 e6 H9 ]' k8 Y

! {; w+ S; ], S5 `& W, iВот конечный рабочий вариант квеста:
8 C% ~/ x7 d4 E+ R' @, ^
  1. import sys. C0 Q  K- {2 k8 S: r
  2. from net.sf.l2j.gameserver.model.quest import State
    4 ]( j2 |( Y' P+ q1 F
  3. from net.sf.l2j.gameserver.model.quest import QuestState
    & H) u# T& c, S+ c9 D
  4. from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest
    % e% n% n9 n: n  N2 o4 R

  5. " `& B; I" b) E; Y
  6. KELTIR_NPC_ID = 12082
    2 N% v# ~- O* C4 K6 l4 n" r* ^
  7. FANGS_ITEM_ID = 1859
    7 {9 \! W/ n5 x3 F
  8. DROP_RATE    = 500000
      F/ _$ p3 I7 t+ l9 d, X& `
  9. 3 l  q) }( w4 X2 @9 z  m
  10. WORLD_MAP_ITEM_ID = 1665: {* U! Q& e, z

  11. + O; a0 e( w, n
  12. def getCount(st) :% m. d9 z( a. V5 _
  13. return st.getQuestItemsCount(FANGS_ITEM_ID)
    / t# P2 E2 Z1 j; m) R7 g
  14. 3 q2 m9 k1 I. r# X$ w7 o5 P# [; ]
  15. def completed(st) :
    % k: F" }  b8 L
  16. st.setState(COMPLETED)
    & N5 o$ Z" X- Y7 t% |
  17. st.clearQuestDrops()
    1 u& s+ `' a3 w3 O+ ?; A+ t5 {3 M
  18. st.takeItems(FANGS_ITEM_ID,-1)
    3 e/ `) J1 k8 k4 E) x% [9 N
  19. st.giveItems(WORLD_MAP_ITEM_ID,1): g3 L# v, q$ M$ ?/ P  X# _
  20. st.exitQuest(False)) s% t/ B, g. F5 P) k
  21. return# }0 ^4 g/ c8 I' f0 K: ~

  22. ) V$ r7 Z% o: U2 n7 j) B0 s" y8 q( T. ^
  23. def check(st) :
    $ a+ a, o! ~" @8 i+ m
  24. if getCount(st) >= 4 :7 m/ I! \4 @+ N4 I" t
  25. completed(st)
    3 c/ E# k* E8 @# o
  26. return
    9 U! O9 ~% O/ s9 J
  27. $ S+ \, k& h# p4 `! Z; m
  28. class Quest (JQuest):
    0 e9 z: k) J# q

  29. 6 W: T3 _; f3 U6 E0 ]' a+ @! M
  30. def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)/ }: x9 [- P" K) `0 E( \6 w; ]
  31. 9 W8 b( R1 @- i2 C: T+ ?1 n
  32. def onEvent (self,event,st):8 B: O: |9 ?* e+ h3 [
  33. id = st.getState()
    ; f+ P/ l) s* O0 ]
  34. if id == CREATED : st.setState(STARTED)
    # Y$ k( A3 V2 V# A/ I
  35. elif id == COMPLETED: pass
    8 T( {& s, `/ \6 T
  36. elif id == STARTED : check(st)0 ?+ _! y' F  s; Z) c
  37. return
    2 g8 Q$ G% t* c) d+ N
  38. / _$ i: r; ~0 Z8 ^3 _/ ~
  39. def onKill (self,npcId,st):
    5 Z5 ~( V7 a( `
  40. if npcId == KELTIR_NPC_ID:0 r' C  H" X3 K! ?  x0 B5 x
  41. n = getCount(st)
    0 @3 T8 @! ?6 c2 Y  p9 ?6 D
  42. if n == 0:3 v; V# ?9 {1 L! J3 u) i% I5 E  s5 I1 j3 r
  43. if st.get('chat0') == None :( p2 P& t2 ^7 Y, v: \5 n& J+ m" ~
  44. st.set("chat0", "true")
    . |5 {2 A$ v, m8 J6 w/ A
  45. return "Chat0.htm"
    ; _2 g9 C2 @( Y
  46. elif n == 1:
    ' |  p" g6 E% L, N$ o/ h
  47. if st.get('chat1') == None :, d/ k# l) A0 r' J
  48. st.set("chat1", "true")/ k" U7 z. k1 r  A0 @8 [- ?/ y$ i
  49. return "Chat1.htm"
    % w" L0 [. K8 H1 [) S1 A
  50. elif n >= 4:
    ( M. @2 P6 U) g8 v0 r
  51. return "Chat4.htm"
    ) M8 y, @$ w0 \# [* L; {4 q7 |
  52. return "Collect "+str(n)+" of 4 fangs"( I& O+ G0 N7 W- E& ^& A: U
  53. return3 a) ~$ A- A. C; ~) Q+ d
  54. - P- D# ~2 H" d/ E+ z3 S) ]
  55. QUEST    = Quest(201, "Tutorial", "Tutorial quest")
    # X  [7 [9 b- }2 E; h3 j4 [
  56. CREATED = State('Start',    QUEST)
    9 I8 n: F3 D7 b9 |% e+ u
  57. STARTED = State('Started', QUEST)5 U5 W# h% H$ @) T  U+ X
  58. COMPLETED = State('Completed', QUEST)) U( M/ t# q' n$ I5 d7 K" J0 I' }
  59. 9 N% h1 P8 p8 x2 a1 r& ^) N* [
  60. QUEST.setInitialState(CREATED): I) p4 F# K+ L' K- l6 R) K/ \
  61. QUEST.addStartNpc(7056)
    4 G& K: f( d1 R4 j1 `" ^8 j
  62. QUEST.addStartNpc(7012)7 w/ P2 h' a7 C* i" f1 U
  63. QUEST.addStartNpc(7009)$ d7 H/ W  S+ y5 w# K* V- O* X5 U
  64. QUEST.addStartNpc(7011), q, u) e- p6 V8 a4 e
  65. ( z# r  I6 W! W5 u" L1 s% a7 _2 Y% n
  66. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
    8 `+ P! [3 z' t9 V
  67. STARTED.addKillId(KELTIR_NPC_ID)
    , ^4 L6 s8 s4 F  G
  68. STARTED.addTalkId(7056): F9 Q, L  k. f% ^: ?2 E  @
  69. STARTED.addTalkI d(7012)! j% z" L. f9 ?2 V7 ?) T8 h
  70. STARTED.addTalkId(7009)
    5 l5 c6 }# X% k
  71. STARTED.addTalkId(7011)
Скопировать код
; A6 A  l0 `1 C+ }4 W) k& u
/ B8 z! B, K1 {( U
Чтобы ответить, вам надо авторизироваться в системе Вход | Зарегистрироваться

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

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

638638758

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

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

admin@artace.ru Онлайн

QR-код

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