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

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

Автор: admin    Время: 2024-9-17 19:36
Название: Создаём собственные квесты (часть 2)
Хроники        Interlude1 t. ~/ V& K, ^; z$ s
Сборка        L2j
: k5 N7 N7 p, ?+ uОбратите внимание: в файле htm стартового NCP обязательно должна быть ссылка на квест:
5 ?% ~  Z3 M" v' Q% [  }
  1. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста:5 f& n7 U9 W8 i" K5 u' `5 C9 t
. Z! Y6 r# I/ ?2 G! b
  1. if getCount(st) >= 4 :8 d' q* s% _/ n
  2. completed(st)
    # h: q  s. i: Y2 |" f. Q
  3.   return
    ; B+ D, c: J0 \, s

  4. 6 h: ?9 h2 i  \, j5 w* t3 U3 p
  5. class Quest (JQuest):; A1 ~$ V' m5 L" I
  6.   def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)# Y( @! g" F' o5 X4 S4 A: h/ F0 a
  7.   def onEvent (self,event,st):
    & p; \# w5 m$ F: Q- M9 R5 H4 i
  8. id = st.getState()
    ( O8 |/ {: ^0 w/ X, c9 k* g3 ^5 c
  9. if   id == CREATED  : st.setState(STARTED)! b; }+ z1 N1 m2 d+ O% H+ Z
  10. elif id == COMPLETED: pass
    9 Z4 K4 q2 G& c6 y% _3 ~
  11. elif id == STARTED  : check(st)
    " `% O5 ]! w$ [* n/ N' d
  12. return
    . ^5 E2 C1 w$ I5 f8 X4 H

  13. 5 |( K# r- w2 f+ D9 \0 S
  14. QUEST     = Quest(201,"Tutorial", "Tutorial quest")1 c# \6 C' K; u  f
  15. CREATED   = State('Start',     QUEST)2 S+ M: T6 b) {# Q, R! Z: q1 Q
  16. STARTED   = State('Started',   QUEST)
    6 r! ]  G% z1 ~& z2 ~' N  K+ ?
  17. COMPLETED = State('Completed', QUEST)& D1 [4 d9 f  X, m6 G* G. L

  18. ! z' _0 _+ E- n5 h
  19. QUEST.setInitialState(CREATED)6 h4 l0 y2 w- Y7 _
  20. QUEST.addStartNpc(7056): ]6 w# }+ |! H  h' l, r5 t. V
  21. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Теперь рассмотрим, как это работает.
2 O( a0 F. f& V# t. D& Q3 JИгрок подходит к начальному NCP (в данном случае 7056), нажимает на «Quest». Квест будет создан и состояние квеста перейдет к CREATED и игроку будет показана страничка Start.htm с описанием квеста. Тогда метод onEvent, поле открытия странички Start.htm переведет состояние квеста в STARTED и игроку будет показана страничка Started.htm, где будет опсание того, как найти keltirs и .т.д.
, H, S8 C- i" A0 y7 f
% f+ A# B' s# S
+ h% W- T4 ]  X5 J; r, M8 h
При состоянии STARTED будет зарегистрирован дроп «fangs» при убийстве keltirs. Игрок может вернуться к стартовому NCP и спросить о квесте – метод onEvent будет вызван снова. Если у игрока не хватает необходимого количества предметов, то метод check() не переведет квест в следующее состояние и Started.htm будет показана снова. Но если игрок собрал необходимее количество предметов (в данном случае 4 клыка), то метод check() вызовет метод completed() который переведет квест в новое состояние COMPLETED, заберет все клыки, даст карту мира, т.к. это награда за квест, покажет Completed.htm и завершит квест.% Q2 S* R7 j" {* G4 j

# b5 V' w4 p" b* {3 u

: O- g- @& p/ W' @4 iТеперь давайте сделаем наш квест более похожим на то, что он должен из себя представлять.  y9 K3 j- W" e. Q, P2 @- I' X
Прежде всего у нас есть 3 метода для объявления их в Яве – onTalk, onKill и onEvent. Если методы onTalk и onKill не объявлены, то за них все будет делать метод onEvent, т.е. определять квестовых монстров и вызывать диалоги NCP. Есть примечание, методы onTalk и onKill будут вызывать только диалоги с NCP в зависимости от текущего состояния квеста. Метод onKill будет вызываться только тогда, когда мы убиваем квестового монстра.3 I9 F/ q3 T* {7 z% A$ E

* I( D- H- U5 g+ {. w* G
: L0 w& L. [1 `( g! A
Давайте рассмотрим как вызывается метод onKill при убийстве keltir в состоянии квеста STARTED:
" u- k( T) n( \
  1. STARTED.addKillId(KELTIR_NPC_ID)
Скопировать код
и метод onKill в классе Quest:
9 u. r: I  m+ D8 c% v4 C% B
: \; a; Q3 {' r. G% E9 |4 ?
  1. class Quest (JQuest):5 v/ t! o( Y' z2 U! H' B0 z" }
  2.   ...
    0 y/ K8 d! }3 P3 G) u; r
  3.   def onKill (self,npcId,st):
      ]" w2 u& ]- u& k8 @
  4. if npcId == KELTIR_NPC_ID:
      Y( g6 t) |3 e( z4 q# L
  5.    n = getCount(st)! c1 p4 }. ]1 V& ~5 x" U
  6.    if   n == 0:
    6 b: ^0 A4 u( O: m8 N
  7.        return "Chat0.htm"3 d" C2 U+ w" l
  8.    elif n == 1:! g- W: p+ [8 w2 l# M: l# d3 Y& `- I$ U
  9.        return "Chat1.htm"
    5 E" M% U/ K+ ?! N3 D: X
  10.    elif n >= 4:: j5 w/ D0 {7 \8 [1 q
  11.        return "Chat4.htm"  ?! B5 Z/ Z8 z+ v5 z/ g) I
  12.    return "Collected "+str(n)+" of 4 fangs"2 m1 d' ]) [( s( @
  13. return
Скопировать код
Метод onKill (а так же метод onTalk) имеет следующие параметры:
& G5 Z2 ~( \3 G! ~0 Z' e: S  U: I- S1 @7 ]

% V% r9 N0 q  a. H0 Q: Q& \• self – квест
* p. x& U2 s/ K  Y• npcId – ID NCP, которого мы должны убивать (если это метод onTalk, то ID того NCP, с которым мы должны поговорить).
! e% |1 h* L# H• st – текущее состояние игрока.+ O8 Q, T+ w; T$ O

8 F; @5 D( r' }  V/ t

% O8 R7 |6 M* wВ этом методе мы проверяем и отмечаем, является ли убитый NCP keltir’ом. В основном эта проверка не нужна, т.к. у нас только KELTIR_NPC_ID.
- u& a$ b4 N7 Y+ a) U. s$ c+ o
) e- Z  A# v1 k

  }5 d; J) r" m0 [$ PЗатем проверяем количество предметов (в данном случае количество клыков), и если их вообще нет, то возвращаем строку "Chat0.htm", если только один предмет, то возвращаем строку "Chat1.htm", если же предметов 4 или больше, то "Chat4.htm". Если строка возвращена из методов onEvent, onKill или onTalk, то сервер покажет соответствующие htm. В Chat0.htm может иметь следующий текст: «Вы не имеете ни одного клыка, возвращайтесь позже, когда соберете 4 штуки и бла, бла, бла…», в Chat1.htm может быть следующий текст: «У Вас всего 1 клык, по этому соберите еще…». В Chat4.htm – «Вы собрали необходимое количество предметов, возвращайтесь к вашему тренеру, что бы завершить квест…»
8 P. E* t2 ?$ Z. `: R/ O9 W1 h/ ?# {8 {  \$ U

2 g( Y+ \  N  M2 B- \# l0 U8 d& n- EПримечание: если в строка return начинается с "<html>", то будет показана страничка html с текстом, который стоит далее. Так вместо:
( p; u! w1 J; t2 y- O" Lreturn "Chat4.htm"4 L" l7 H& ~& p9 z- c

! G1 y4 X8 [; P+ @$ n/ _) ?

1 ]% b8 ?# `' q+ Q& n/ b1 iможно поставить:
# ~3 x$ L6 e# @. o/ S
  1. return "<html><body>Return to your trainer to complete the quest</body></html>"
Скопировать код
Так же если строка заканчивается без .htm или в начале нет <html>, то текст будет выведен, как системное сообщение в окне чата. В нашем случае мы сделаем так, что бы при каждом убийстве keltik выводилось системное сообщение: «Собрано N из 4-х клыков».
6 k6 O0 V1 w7 E. M+ X( X. S" i9 |- m9 i. ~$ q" X) Z
8 `5 u9 O: f, _& Y
Наш код для onKill имеет один недостаток. Он будет постоянно показывать Chat0.htm, Chat1.htm и Chat4.htm, нам же необходимо, что бы Chat0.htm и Chat1.htm показывались только один раз. Как нам это сделать? С помощью переменных.
* |; b, W. d$ L' U, q) J1 L" \, a2 y! ~. z5 ]0 A

( }: I( P' H$ b4 Q4 tВ каждом квесте строки могут храниться с помощью переменных. Эти переменные сохраняются в Вашей БД. В каждом методе мы можем назначить, прочитать и удалить переменные. Давайте изменим метод onKill, так что бы каждый диалог вызывался только один раз.
8 ^. h! v9 f: |* l' o0 x& d
  1. def onKill (self,npcId,st):' N0 `# f# [! ^4 M9 y
  2. if npcId == KELTIR_NPC_ID:4 f3 ~0 @$ i+ v- e6 K: E6 w! d
  3. n = getCount(st)) R% m- a% D3 V
  4. if n == 0:) ^4 D5 v$ H  n7 V
  5. if st.get('chat0') == None :
    9 c; R0 h# R$ P7 z
  6. st.set("chat0", "true")% d3 x# A$ U' W6 p( f- d/ y
  7. return "Chat0.htm"9 x  G  B) S9 `9 L( c2 \
  8. elif n == 1:' [( \3 N3 ~) A, [$ V
  9. if st.get('chat1') == None :) f& S4 e+ [1 p5 ?4 M4 O
  10. st.set("chat1", "true")
    0 D$ t0 c) X! S7 {
  11. return "Chat1.htm"
    , F# y! S8 X, ?" M8 P8 {3 K$ ?
  12. elif n >= 4:2 `: p$ U3 Z7 c( t& R# S
  13. return "Chat4.htm"' \1 D! c, U& V) E
  14. return "Collected "+str(n)+" of 4 fangs"! d" `' z. f3 d% t; _+ ~
  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.; g. f' X$ G( R( N. R

% i" E8 z1 s! A1 Q+ r! [! w. g
. ]* g' \8 G6 w3 W+ [
Вот конечный рабочий вариант квеста:
5 d1 I4 y6 x- |
  1. import sys
    , \2 t8 `9 a( O1 ]% e; v
  2. from net.sf.l2j.gameserver.model.quest import State1 ]9 P  n) L* t- g
  3. from net.sf.l2j.gameserver.model.quest import QuestState
    " k: H" q7 z% L0 h
  4. from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest
      H+ a1 @/ n5 K, O

  5. 2 w! O; E- \8 K$ C" c
  6. KELTIR_NPC_ID = 12082
    4 z6 C# D8 U8 G! @" R/ a- k# |
  7. FANGS_ITEM_ID = 1859
    0 F' D) r) A; F
  8. DROP_RATE    = 500000
    $ i' k9 O- Q) E9 K& I
  9. ( F2 G2 ?  l8 z3 H( a
  10. WORLD_MAP_ITEM_ID = 1665
    ; F9 H6 W' O. e& ^
  11. & X$ j* Q6 f" Q  P+ W
  12. def getCount(st) :
    1 U& |1 A3 ^+ X/ Z: ^: c. O
  13. return st.getQuestItemsCount(FANGS_ITEM_ID)
    3 \! W/ h! d9 E7 J+ u

  14. , a4 }) h; v* L
  15. def completed(st) :5 F/ D4 n- O( Q
  16. st.setState(COMPLETED)4 L: E+ r- X3 y' |8 Y# w
  17. st.clearQuestDrops()
    ! c0 D5 D0 N% [  X8 n
  18. st.takeItems(FANGS_ITEM_ID,-1)8 a) }5 N# D9 p6 A$ u) N# E
  19. st.giveItems(WORLD_MAP_ITEM_ID,1)$ ?+ T) {  h8 y7 @6 }: g# O
  20. st.exitQuest(False)
    9 L: z4 i& ^$ \% M
  21. return) W  T" Y) c$ K  Z  W$ s
  22. 4 }+ `, A/ o2 Y, {. ^+ ^  f
  23. def check(st) :
    . {: J( M7 k8 j% [; Q
  24. if getCount(st) >= 4 :) ]" e7 m3 D+ N
  25. completed(st)
    / w4 g% {& @7 T
  26. return
    5 l* Q# C) V" E" M" Y6 Y' m  d3 t

  27. - k. N$ X& Z& o) E9 |2 v/ v6 m: ~0 A
  28. class Quest (JQuest):. V; l2 J) `4 j2 g9 @9 g. K2 D

  29. & N& E& r3 O; f
  30. def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)( Q3 f8 H8 x. Y" G" D% X2 o3 Z
  31. . t' Q& @+ R7 F0 T( ~5 Y# |) N6 o
  32. def onEvent (self,event,st):1 I; J3 m& F5 W, v4 {
  33. id = st.getState()2 H: k  k- F( G5 y  h, d- q* h
  34. if id == CREATED : st.setState(STARTED)
    % R+ ~: C& {- R' X$ t
  35. elif id == COMPLETED: pass3 g: @9 P- S$ ~, o
  36. elif id == STARTED : check(st)% p% g8 o7 _0 C
  37. return
    & l: ~, J6 ?% k+ U4 H  U

  38. " l4 f. I, @5 l# n
  39. def onKill (self,npcId,st):
    8 ^7 ]" o# |, y
  40. if npcId == KELTIR_NPC_ID:! n; Y8 E% k* J, C! B
  41. n = getCount(st)1 v. A) L5 Q" N& m" ~0 x; G8 D& n8 X
  42. if n == 0:8 Z, d% x" _0 P5 A) m+ b* u
  43. if st.get('chat0') == None :  I. X! G! C! @9 ~) \0 L6 s
  44. st.set("chat0", "true")
    - t0 Z, K8 S8 a
  45. return "Chat0.htm"& v5 j& R7 i+ ?9 _- G! b
  46. elif n == 1:
    " Z  }9 E, |" u/ {
  47. if st.get('chat1') == None :
    * |+ r6 R' {$ g: }; R& q
  48. st.set("chat1", "true")
    ' ]' N# ~6 p# |9 k  s+ x* c. }
  49. return "Chat1.htm"% B# C2 q' d/ T$ ^, f
  50. elif n >= 4:: X0 F0 u- g+ r: C( N
  51. return "Chat4.htm"
    # w6 y9 v! C+ R/ ^. d9 l
  52. return "Collect "+str(n)+" of 4 fangs"$ u' e2 C0 z' O0 b
  53. return
    % [. B" F6 s( C
  54. + K8 r6 s) x" o, e% \1 H9 J
  55. QUEST    = Quest(201, "Tutorial", "Tutorial quest")& D! T- _5 U) S' X: x
  56. CREATED = State('Start',    QUEST)
    7 _* b/ D* g8 |
  57. STARTED = State('Started', QUEST)" n+ h9 O/ d; N
  58. COMPLETED = State('Completed', QUEST)
    % c" M6 a7 E' ]/ M5 N6 p, S
  59. : v2 A: C. @6 ~/ w( d) u+ T, p
  60. QUEST.setInitialState(CREATED)9 k* V9 M/ R. c. k9 d
  61. QUEST.addStartNpc(7056)3 N% x  Y  G& {% Y1 n
  62. QUEST.addStartNpc(7012)* Z6 `( G7 D0 W8 Z% ^6 m- y5 V
  63. QUEST.addStartNpc(7009)1 e' s. s: G3 A3 V) ~: _8 Q
  64. QUEST.addStartNpc(7011)% |) p) g7 @( i9 E: Q3 J0 N3 ]

  65. . Z& ]/ u6 ~9 P$ r8 ^+ G
  66. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)6 }' u1 Z0 L* u. z! Q& {
  67. STARTED.addKillId(KELTIR_NPC_ID)
    & R# {0 g$ p9 b+ ?% W8 @6 v# d
  68. STARTED.addTalkId(7056)
    5 e( F# J0 W4 s
  69. STARTED.addTalkI d(7012)
    ( s, Z4 o% q$ }* K% e5 U7 b
  70. STARTED.addTalkId(7009)
    0 ?# A0 }3 M. F. j
  71. STARTED.addTalkId(7011)
Скопировать код
# n. X* C$ W( `& j- T

' l% g# k" K" }




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