Top.Mail.Ru

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

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

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

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

x
Хроники        Interlude
# [0 g4 b0 i. C- \% QСборка        L2j' Z3 g5 U0 [3 m5 M6 P& G3 C5 K# }
Обратите внимание: в файле htm стартового NCP обязательно должна быть ссылка на квест:. _" D. L$ P# v( `
  1. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста:
8 o# \* W7 s! B1 |  C" S, `) i2 q: D- }
  1. if getCount(st) >= 4 :
    ! X6 X3 d0 P( v! t
  2. completed(st)
    ' `* g! X, S# Q; I9 q
  3.   return
    5 x$ e/ M- J9 M  W# \7 g$ F3 r
  4. # ^$ p5 z' r  b. Z( ?! \* {
  5. class Quest (JQuest):, i& z, _' g# U+ Q1 P7 J
  6.   def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)
    ) |$ e7 U/ X# S6 E
  7.   def onEvent (self,event,st):! [9 @" o8 G. Z! O" l# h
  8. id = st.getState()) t) @; k6 c1 g/ N2 E
  9. if   id == CREATED  : st.setState(STARTED)6 j6 q" y4 U# T2 T, N. Z
  10. elif id == COMPLETED: pass
    3 H; [% U. [1 K* s6 |  W' ~8 k
  11. elif id == STARTED  : check(st)
    6 C. J9 A5 t1 ~  }* z
  12. return
    9 F* R7 ]7 f- V" {

  13. 6 f/ o6 _" {9 _
  14. QUEST     = Quest(201,"Tutorial", "Tutorial quest")
    : j* Z% a2 u! g" ~
  15. CREATED   = State('Start',     QUEST)
    ; k' \& {2 Y: w  N& B" m3 }
  16. STARTED   = State('Started',   QUEST)
    2 c9 `. ~* M& e* K4 h# E4 I
  17. COMPLETED = State('Completed', QUEST)
      \6 |4 G5 k, ^7 `7 r7 t

  18. ' \! x* Y- a# {3 l! K% e# \+ S' Y
  19. QUEST.setInitialState(CREATED)& k; E3 A! ]' R/ j: {; a1 x
  20. QUEST.addStartNpc(7056)1 I) d# `7 e3 Q* I5 s( a
  21. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
Скопировать код
Теперь рассмотрим, как это работает.2 k& v; }. G0 q+ X
Игрок подходит к начальному NCP (в данном случае 7056), нажимает на «Quest». Квест будет создан и состояние квеста перейдет к CREATED и игроку будет показана страничка Start.htm с описанием квеста. Тогда метод onEvent, поле открытия странички Start.htm переведет состояние квеста в STARTED и игроку будет показана страничка Started.htm, где будет опсание того, как найти keltirs и .т.д.
7 |+ l% j$ b) d2 k  b$ o: N4 p0 o" R% s
# \0 j5 y' E4 `. ?& H6 z5 R' t
При состоянии STARTED будет зарегистрирован дроп «fangs» при убийстве keltirs. Игрок может вернуться к стартовому NCP и спросить о квесте – метод onEvent будет вызван снова. Если у игрока не хватает необходимого количества предметов, то метод check() не переведет квест в следующее состояние и Started.htm будет показана снова. Но если игрок собрал необходимее количество предметов (в данном случае 4 клыка), то метод check() вызовет метод completed() который переведет квест в новое состояние COMPLETED, заберет все клыки, даст карту мира, т.к. это награда за квест, покажет Completed.htm и завершит квест.0 b& A7 _9 x2 ~# j
2 R, o7 b. D3 k/ G

: \" T# r4 j6 Q  `Теперь давайте сделаем наш квест более похожим на то, что он должен из себя представлять.
7 M* e4 o3 k8 @: YПрежде всего у нас есть 3 метода для объявления их в Яве – onTalk, onKill и onEvent. Если методы onTalk и onKill не объявлены, то за них все будет делать метод onEvent, т.е. определять квестовых монстров и вызывать диалоги NCP. Есть примечание, методы onTalk и onKill будут вызывать только диалоги с NCP в зависимости от текущего состояния квеста. Метод onKill будет вызываться только тогда, когда мы убиваем квестового монстра.
# S, R& n+ b' F5 I% ?8 A+ Y) n. c% H9 h; P

4 @' D/ R4 t* [  }; P. g# xДавайте рассмотрим как вызывается метод onKill при убийстве keltir в состоянии квеста STARTED:" L* ?& B6 f8 t& j5 e7 H
  1. STARTED.addKillId(KELTIR_NPC_ID)
Скопировать код
и метод onKill в классе Quest:' H( b0 n. D" `) r* ~4 ^& F
5 Y4 ~6 v3 M! I$ C
  1. class Quest (JQuest):* m4 d% e: V/ O) H2 [
  2.   ...1 w" Z, S# l+ N. e5 d; K- A! k2 Q
  3.   def onKill (self,npcId,st):
    2 `( E3 v. e% \  Z& ^  V
  4. if npcId == KELTIR_NPC_ID:7 V% \- `. E/ j
  5.    n = getCount(st)
    4 p" ?3 c$ T) R# i2 j5 {
  6.    if   n == 0:* u! V! u% W5 W
  7.        return "Chat0.htm"7 i( M, k9 w" V5 |  I
  8.    elif n == 1:7 `$ I6 i3 P, N7 @
  9.        return "Chat1.htm") n! q4 X- h- o+ m
  10.    elif n >= 4:
    " h5 L  w! L1 `/ N; R& h) w
  11.        return "Chat4.htm"
    - V( m! |# `; l$ w5 p4 b
  12.    return "Collected "+str(n)+" of 4 fangs", F1 _4 _& l4 W4 f, U
  13. return
Скопировать код
Метод onKill (а так же метод onTalk) имеет следующие параметры:- _9 F4 {* R. F7 N, I! T
7 C( ^+ E* X2 L

& m( i- J. J; j2 m; r9 P• self – квест! f8 X" ?+ y! R0 p  X  G
• npcId – ID NCP, которого мы должны убивать (если это метод onTalk, то ID того NCP, с которым мы должны поговорить).1 x1 I9 E  y6 @$ I$ l
• st – текущее состояние игрока.
( v3 Q' b  S- E0 B
; R* }4 y; K, p1 |/ R

7 {2 n' ?! y/ j" y  RВ этом методе мы проверяем и отмечаем, является ли убитый NCP keltir’ом. В основном эта проверка не нужна, т.к. у нас только KELTIR_NPC_ID.
5 r% C3 S: S/ Y2 D$ m* |7 N, {0 `# P  _6 _1 [* Z

+ G6 ~; m, X+ ZЗатем проверяем количество предметов (в данном случае количество клыков), и если их вообще нет, то возвращаем строку "Chat0.htm", если только один предмет, то возвращаем строку "Chat1.htm", если же предметов 4 или больше, то "Chat4.htm". Если строка возвращена из методов onEvent, onKill или onTalk, то сервер покажет соответствующие htm. В Chat0.htm может иметь следующий текст: «Вы не имеете ни одного клыка, возвращайтесь позже, когда соберете 4 штуки и бла, бла, бла…», в Chat1.htm может быть следующий текст: «У Вас всего 1 клык, по этому соберите еще…». В Chat4.htm – «Вы собрали необходимое количество предметов, возвращайтесь к вашему тренеру, что бы завершить квест…»
/ y  [8 N" H" |5 I
; ?; \0 o7 y" j- c# J

1 d6 X/ S- Q5 o6 k6 tПримечание: если в строка return начинается с "<html>", то будет показана страничка html с текстом, который стоит далее. Так вместо:" H# F( ^+ M3 b: @
return "Chat4.htm"
" l9 X. j& w$ A+ u( t; Q
) S1 J8 [  c; ^5 b

/ U! a2 Q. f4 t! a5 h* ~* a# h! nможно поставить:
, ?' m  e& G9 a$ A: f, p) K
  1. return "<html><body>Return to your trainer to complete the quest</body></html>"
Скопировать код
Так же если строка заканчивается без .htm или в начале нет <html>, то текст будет выведен, как системное сообщение в окне чата. В нашем случае мы сделаем так, что бы при каждом убийстве keltik выводилось системное сообщение: «Собрано N из 4-х клыков».
* Y" k: q7 ]2 w. s! y* o
  a; D* N5 v* j% V; t

: `/ c6 C" f0 [( q5 [Наш код для onKill имеет один недостаток. Он будет постоянно показывать Chat0.htm, Chat1.htm и Chat4.htm, нам же необходимо, что бы Chat0.htm и Chat1.htm показывались только один раз. Как нам это сделать? С помощью переменных.
" a9 [: [8 Y8 ~2 ]  x2 t$ k* U( K6 M  Y! B! K! J
2 U! X" T( g0 z! w* w2 D& C
В каждом квесте строки могут храниться с помощью переменных. Эти переменные сохраняются в Вашей БД. В каждом методе мы можем назначить, прочитать и удалить переменные. Давайте изменим метод onKill, так что бы каждый диалог вызывался только один раз.
' [) ]# s, G! H0 d
  1. def onKill (self,npcId,st):
    $ \5 l# K/ e7 u& r+ c7 H6 m) B
  2. if npcId == KELTIR_NPC_ID:- c9 r4 J4 I' l- ?- _# _
  3. n = getCount(st)9 t4 Y+ c# \6 D( o, m* |
  4. if n == 0:
    1 H" \% l6 Y+ ^& }2 o) E# |% S/ X8 T
  5. if st.get('chat0') == None :
    5 V6 M9 b) \2 P! f5 W( |
  6. st.set("chat0", "true")
    8 q& T' G4 I  C8 s" m9 {  D) o0 f
  7. return "Chat0.htm"0 X# V0 w* V& g  G; }
  8. elif n == 1:
    ) W8 }& w0 [' x5 k4 U' J9 U7 E/ |3 n
  9. if st.get('chat1') == None :
    9 ~5 q7 V, H' e; q* F
  10. st.set("chat1", "true")
    6 K& r  t4 X- m  }
  11. return "Chat1.htm"
    * G- y9 P* @8 o7 z5 a
  12. elif n >= 4:- o" ^) e$ X8 c) m  x4 `1 O
  13. return "Chat4.htm": ~6 J# \, y; O5 \9 p. G$ `
  14. return "Collected "+str(n)+" of 4 fangs"$ ]0 y+ p7 e- [* l3 O" K2 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.
* H( v4 d: A' D2 T5 @  Z! ?5 _  F3 F) w- g  d  Z
% j" r: U2 ]9 h. t/ c
Вот конечный рабочий вариант квеста:
2 b: a) c# b- [9 ?+ L
  1. import sys
    : n5 {: r5 m* F, e" Z6 [, s
  2. from net.sf.l2j.gameserver.model.quest import State- K, L5 P9 S1 D$ u
  3. from net.sf.l2j.gameserver.model.quest import QuestState" @0 b9 [1 n7 |: O6 n7 p& a
  4. from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest
    - \% F0 x. g; j: I2 ~

  5. + f* |" k+ z4 S8 v! h" h
  6. KELTIR_NPC_ID = 12082& k6 A" ~8 [% k  S! G$ g% u
  7. FANGS_ITEM_ID = 18596 I4 s* g2 ?$ U% Y, ^
  8. DROP_RATE    = 500000, u! R# v1 E% L5 M: l
  9. * W" E2 q6 F) h6 ~# c8 p6 y
  10. WORLD_MAP_ITEM_ID = 16651 t3 D% S, S9 g/ K; Y

  11. " L# M; j/ v. Z+ w9 m9 K& i
  12. def getCount(st) :
    - K/ v& s; L3 @% A2 T/ U$ Q5 w6 {
  13. return st.getQuestItemsCount(FANGS_ITEM_ID); I# s$ N- n/ }( J
  14. . {7 ^5 V* N" H
  15. def completed(st) :
    : l# [" r( h8 @4 k9 g9 P, b+ q, x( h
  16. st.setState(COMPLETED)! ~8 n5 P# z0 r. a0 o; [
  17. st.clearQuestDrops()
    + f0 I7 ~+ Y" Y; G# k8 _  J' S5 a1 {
  18. st.takeItems(FANGS_ITEM_ID,-1)' U* `# n4 l1 {3 s$ q
  19. st.giveItems(WORLD_MAP_ITEM_ID,1)
    2 \; k1 x' t- x$ Y" Z6 \" t- n4 j
  20. st.exitQuest(False)( B" {0 h0 v3 J) T
  21. return% O$ {  o, N4 {8 t# B3 w& c) t
  22. $ l: K* E2 @6 Y. x
  23. def check(st) :
    ; q! \" m* T) R7 `
  24. if getCount(st) >= 4 :0 E4 M' `* A* W1 \) W( z. P( v
  25. completed(st)' C' I  N9 k4 C  J$ A& }
  26. return6 A2 m5 p3 ]; V  |5 R' H3 R1 W
  27. ) g% w9 Y7 E$ K( P8 R  q! D7 U% u
  28. class Quest (JQuest):5 [1 a" {7 Z3 B8 O/ _) a
  29. . e! R% L& q" G, e6 v! V0 U# g) T
  30. def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)
    0 p% J* Z* B8 R3 ~6 K0 l+ p3 D! v

  31. % A; j) ^& y+ M7 I- W; T' F3 w
  32. def onEvent (self,event,st):, y" F$ E4 p# C+ q5 l1 B
  33. id = st.getState()+ S8 B+ ]9 @. }  t
  34. if id == CREATED : st.setState(STARTED). [. `7 K# C1 x$ \  G4 _6 \) p
  35. elif id == COMPLETED: pass
    0 m0 r; ?/ `' A8 N1 u! j* Q
  36. elif id == STARTED : check(st)0 y  ?, O) e% U
  37. return
    , C$ d8 b. j$ v1 R# T4 l2 p$ ^
  38. 0 R5 A6 O+ H  q
  39. def onKill (self,npcId,st):% y) W- [+ t  c1 h
  40. if npcId == KELTIR_NPC_ID:; {, g, J/ w  S# O! Z9 q- {
  41. n = getCount(st)
    5 c* A* K; I$ `6 Q7 U+ B8 H
  42. if n == 0:) g; h- i/ I7 T3 a6 v% a, H5 G' w5 X
  43. if st.get('chat0') == None :5 j4 ~# s% e, q" C$ K0 y. j% ~: b
  44. st.set("chat0", "true")
    - n- _. H* ~  O/ u. R: t: F- }
  45. return "Chat0.htm"* l- L3 g- N* @$ ^/ G! _
  46. elif n == 1:
      ~0 ?3 d5 _* a3 a" L
  47. if st.get('chat1') == None :, T9 o& |' f$ q# b# u7 P
  48. st.set("chat1", "true")6 k7 w& o1 r! ?+ F: X
  49. return "Chat1.htm"% [! `  _0 k5 i/ U
  50. elif n >= 4:  {2 l' W5 R& i8 ]# O2 S- k' h
  51. return "Chat4.htm"+ Y, C( E2 }( J# K  w+ ?& B- m8 Z
  52. return "Collect "+str(n)+" of 4 fangs"
    , _. O' u- V3 L1 K" o" R+ a! s
  53. return$ P" a' `4 d( Z( |5 }# `" {& G! a8 J: ?

  54. ) Y. h; F" C$ V: q
  55. QUEST    = Quest(201, "Tutorial", "Tutorial quest"), W: \1 S0 i* B* @5 j- l1 t
  56. CREATED = State('Start',    QUEST)
    5 u# D( M; k2 I1 G! m4 L' A5 c
  57. STARTED = State('Started', QUEST)
    5 s6 j- s% L2 @' O: A: p
  58. COMPLETED = State('Completed', QUEST)) \( O- M6 H- U/ S2 y
  59. ' V* ]  I: t, W7 p
  60. QUEST.setInitialState(CREATED)5 |$ H2 p+ n7 t
  61. QUEST.addStartNpc(7056)% V. f. e1 [4 \9 j
  62. QUEST.addStartNpc(7012)# q  ~( H; E$ ^$ X# B$ l
  63. QUEST.addStartNpc(7009)
    ( l5 |9 M$ a* y) c
  64. QUEST.addStartNpc(7011)- \5 b7 v" |2 d8 G# c
  65. ' m. @3 N% v: m/ R: C- l$ }
  66. STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
    1 T. g! Y# q6 y9 X* i- E
  67. STARTED.addKillId(KELTIR_NPC_ID)! G! ~3 ~. O1 {' a+ k
  68. STARTED.addTalkId(7056)
    : w+ {1 w9 l( |- }  G2 b4 Q
  69. STARTED.addTalkI d(7012)8 d* {9 e, `! B% o. Q" Z5 ~  f/ t
  70. STARTED.addTalkId(7009)( l) \% A- D( ]
  71. STARTED.addTalkId(7011)
Скопировать код

+ `' ]: F! ~3 o" _8 S% @: k0 r( l  @6 R9 Z% w/ u
Чтобы ответить, вам надо авторизироваться в системе Вход | Зарегистрироваться

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

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

638638758

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

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

admin@artace.ru Онлайн

QR-код

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