мануал. Создание квестов - Форум администраторов игровых серверов
Форум администраторов игровых серверов StormWall - Защита от DDos атак
Регистрация Мнения Справка Пользователи Календарь Все разделы прочитаны
Вернуться   Форум администраторов игровых серверов > MMO > Lineage II > Тех-документация

Тех-документация Статьи по редактированию, компиляции и настройки ява серверов Lineage 2

Ответ
Опции темы
Непрочитано 14.11.2007, 22:48   #1
Пользователь

Автор темы (Топик Стартер) мануал. Создание квестов

Первое что нужно сделать, это добавить необходимые Java классы в квест. (net.sf.l2j.gameserver.model.quest).

PHP код:
import sys
from net
.sf.l2j.gameserver.model.quest import State
from net
.sf.l2j.gameserver.model.quest import QuestState
from net
.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest 
Класс QuestJython (импортирован под названием JQuest) содержит информацию о квестах.
Класс State используется для того, что бы описать информацию о состоянии квеста.
Класс QuestState применяется непосредственно для отслеживания состояния игрока, о ходе выполнения квеста или части квеста.

Затем необходимо добавить несколько констант, что сделает квест удобочитаемым. Если этого не сделать, то могут возникнуть сложности с редактированием квеста в будущем.
Константы нашего квеста – это ID NCP и итемов.

PHP код:
KELTIR_NPC_ID 12082
FANGS_ITEM_ID 
1859
DROP_RATE     
500000
WORLD_MAP_ITEM_ID 
1665 
Затем объявите несколько вспомогательных функций.

Функция для получения количества квестовых предметов (keltir fangs) у игрока. (st должна быть в QuestState):

PHP код:
def getCount(st) :
  return 
st.getQuestItemsCount(FANGS_ITEM_ID
Функция для завершения квеста (st должна быть в QuestState):

PHP код:
def completed(st) :
  
st.setState(COMPLETED)
  
st.clearQuestDrops()
  
st.takeItems(FANGS_ITEM_ID,-1)
  
st.giveItems(WORLD_MAP_ITEM_ID,1)
  
st.exitQuest(False)
  return 
Тут объявляем квест выполненным, сбрасываем квестовый дроп, забираем все клыки у игрока и даем ему награду. Затем сообщаем серверу, что квест завершен и больше не повторяется. (st.exitQuest(False))

И наконец вспомогательная функция для проверки необходимого количества клыков у игрока для завершения квеста. (st должна быть в QuestState):

PHP код:
def check(st) :
  if 
getCount(st) >= :
    
completed(st)
  return 
Затем мы объявляем непосредственно сам класс quest. Quest – класс python, который расширяет java класс net.sf.l2j.gameserver.model.quest.jython.QuestJyth on. Затем мы объявляем метод onEvent, который вызывается Явой, если квест кто то начал.

PHP код:
class Quest (JQuest):

  
def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)

  
def onEvent (self,event,st):
    
id st.getState()
    if   
id == CREATED  st.setState(STARTED)
    
elif id == COMPLETEDpass
    elif id 
== STARTED  check(st)
    return 
Метод init – это конструктор Jython класса, который вызывает конструктор Java класса. Конструктор имеет параметры:
• self – ссылка на себя.
• id – численный идентификатор квеста для клиента.
• name – имя квеста, которое будет опубликовано непосредственно с самом сервере.
• descr – имя описания квеста, показываемое игроку, когда берет квест у NCP, у которого можно взять, кроме этого квеста, еще и другой.

Метод onEvent вызывается от Явы. Осуществляет начало квеста. Имеет параметры:
• self – ссылка непосредственно на Tutorial Quest
• event – строка для идентификации эвента для Явы.
• st – ссылка на QuestState, для отслеживания текущего состояния игрока.

В первой строке идет проверка на текущее состояние квеста непосредственно для игрока и состояние запивается в переменную ‘id’.
Если квест только взят, то объявляем начало квеста (if id == CREATED : st.setState(STARTED)).
Если квест уже выполнен, то ничего не делаем elif id == COMPLETED: pass)
Если квест уже начат (STARTED), то вызывается функция проверки (check(), определенная выше) количества клыков у персонажа для завершения квеста. Мы не проверяем переменную ‘event’, т.к. в нашем примере (Tutorial quest) все события происходят от разговоров с NCP. Метод onEvent вызывается, если поговорить с NCP.

И наконец, когда скелет квеста определен, мы создаем сам квест (и определяем его в самом сервере) и объявляем его.

PHP код:
QUEST     Quest(201,"Tutorial""Tutorial quest")
CREATED   State('Start',     QUEST)
STARTED   State('Started',   QUEST)
COMPLETED State('Completed'QUEST
Квест будет иметь id клиента – 201, идентификатор «Tutorial» и описание «Tutorial quest». Так же будет иметь 3 состояния: CREATED, STARTED, COMPLETED. Имена состояний могут использоваться для автоматического поиска необходимых .htm. Например для CREATED будет соответствовать 'Start.htm', для STARTED – ‘Started.htm’ и для COMPLETED будет показана 'Completed.htm'. Имена состояний используются так же для хранения состояния выполнения квеста в БД, когда игрок выходит из игры, так что имена не должны повторятся в пределах одного квеста.

Так же мы должны определить начальное состояние квеста, когда игрок его только взял, и так же стартового NCP.

PHP код:
QUEST.setInitialState(CREATED)
QUEST.addStartNpc(7056
Обратите внимание: в файле htm стартового NCP обязательно должна быть ссылка на квест:

PHP код:
<a action="bypass -h npc_%objectId%_Quest"
Теперь необходимо добавить дроп для этого квеста при состоянии STARTED, для того, что бы получить необходимые вещи.

PHP код:
STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE
Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста:

PHP код:
import sys
from net
.sf.l2j.gameserver.model.quest import State
from net
.sf.l2j.gameserver.model.quest import QuestState
from net
.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest

KELTIR_NPC_ID 
12082
FANGS_ITEM_ID 
1859
DROP_RATE     
500000
WORLD_MAP_ITEM_ID 
1665


def getCount
(st) :
  return 
st.getQuestItemsCount(FANGS_ITEM_ID)

def completed(st) :
  
st.setState(COMPLETED)
  
st.clearQuestDrops()
  
st.takeItems(FANGS_ITEM_ID,-1)
  
st.giveItems(WORLD_MAP_ITEM_ID,1)
  
st.exitQuest(False)
  return

def check(st) :
  if 
getCount(st) >= :
    
completed(st)
  return

class 
Quest (JQuest):

  
def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)

  
def onEvent (self,event,st):
    
id st.getState()
    if   
id == CREATED  st.setState(STARTED)
    
elif id == COMPLETEDpass
    elif id 
== STARTED  check(st)
    return

QUEST     Quest(201,"Tutorial""Tutorial quest")
CREATED   State('Start',     QUEST)
STARTED   State('Started',   QUEST)
COMPLETED State('Completed'QUEST)

QUEST.setInitialState(CREATED)
QUEST.addStartNpc(7056)

STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE
Теперь рассмотрим, как это работает.
Игрок подходит к начальному NCP (в данном случае 7056), нажимает на «Quest». Квест будет создан и состояние квеста перейдет к CREATED и игроку будет показана страничка Start.htm с описанием квеста. Тогда метод onEvent, поле открытия странички Start.htm переведет состояние квеста в STARTED и игроку будет показана страничка Started.htm, где будет опсание того, как найти keltirs и .т.д.

При состоянии STARTED будет зарегистрирован дроп «fangs» при убийстве keltirs. Игрок может вернуться к стартовому NCP и спросить о квесте – метод onEvent будет вызван снова. Если у игрока не хватает необходимого количества предметов, то метод check() не переведет квест в следующее состояние и Started.htm будет показана снова. Но если игрок собрал необходимее количество предметов (в данном случае 4 клыка), то метод check() вызовет метод completed() который переведет квест в новое состояние COMPLETED, заберет все клыки, даст карту мира, т.к. это награда за квест, покажет Completed.htm и завершит квест.

Теперь давайте сделаем наш квест более похожим на то, что он должен из себя представлять.

Прежде всего у нас есть 3 метода для объявления их в Яве – onTalk, onKill и onEvent. Если методы onTalk и onKill не объявлены, то за них все будет делать метод onEvent, т.е. определять квестовых монстров и вызывать диалоги NCP. Есть примечание, методы onTalk и onKill будут вызывать только диалоги с NCP в зависимости от текущего состояния квеста. Метод onKill будет вызываться только тогда, когда мы убиваем квестового монстра.

Давайте рассмотрим как вызывается метод onKill при убийстве keltir в состоянии квеста STARTED:


PHP код:
STARTED.addKillId(KELTIR_NPC_ID
и метод onKill в классе Quest:

PHP код:
class Quest (JQuest):
  ...
  
def onKill (self,npcId,st):
    if 
npcId == KELTIR_NPC_ID:
      
getCount(st)
      if   
== 0:
          return 
"Chat0.htm"
      
elif n == 1:
          return 
"Chat1.htm"
      
elif n >= 4:
          return 
"Chat4.htm"
      
return "Collected "+str(n)+" of 4 fangs"
    
return 

Метод onKill (а так же метод onTalk) имеет следующие параметры:
• self – квест
• npcId – ID NCP, которого мы должны убивать (если это метод onTalk, то ID того NCP, с которым мы должны поговорить).
• st – текущее состояние игрока.

В этом методе мы проверяем и отмечаем, является ли убитый NCP keltir’ом. В основном эта проверка не нужна, т.к. у нас только KELTIR_NPC_ID.

Затем проверяем количество предметов (в данном случае количество клыков), и если их вообще нет, то возвращаем строку "Chat0.htm", если только один предмет, то возвращаем строку "Chat1.htm", если же предметов 4 или больше, то "Chat4.htm". Если строка возвращена из методов onEvent, onKill или onTalk, то сервер покажет соответствующие htm. В Chat0.htm может иметь следующий текст: «Вы не имеете ни одного клыка, возвращайтесь позже, когда соберете 4 штуки и бла, бла, бла…», в Chat1.htm может быть следующий текст: «У Вас всего 1 клык, по этому соберите еще…». В Chat4.htm – «Вы собрали необходимое количество предметов, возвращайтесь к вашему тренеру, что бы завершить квест…»

Примечание: если в строка return начинается с "<html>", то будет показана страничка html с текстом, который стоит далее. Так вместо:

PHP код:
return "Chat4.htm" 
можно поставить:

PHP код:
return "<html><body>Return to your trainer to complete the quest</body></html>" 
Letov вне форума Ответить с цитированием
Сказали спасибо:
Непрочитано 14.11.2007, 22:48   #2
Пользователь

Автор темы (Топик Стартер)

Так же если строка заканчивается без .htm или в начале нет <html>, то текст будет выведен, как системное сообщение в окне чата. В нашем случае мы сделаем так, что бы при каждом убийстве keltik выводилось системное сообщение: «Собрано N из 4-х клыков».

Наш код для onKill имеет один недостаток. Он будет постоянно показывать Chat0.htm, Chat1.htm и Chat4.htm, нам же необходимо, что бы Chat0.htm и Chat1.htm показывались только один раз. Как нам это сделать? С помощью переменных.

В каждом квесте строки могут храниться с помощью переменных. Эти переменные сохраняются в Вашей БД. В каждом методе мы можем назначить, прочитать и удалить переменные. Давайте изменим метод onKill, так что бы каждый диалог вызывался только один раз.

Код:
def onKill (self,npcId,st):
    if npcId == KELTIR_NPC_ID:
      n = getCount(st)
      if   n == 0:
        if st.get('chat0') == None :
          st.set("chat0", "true")
          return "Chat0.htm"
      elif n == 1:
        if st.get('chat1') == None :
          st.set("chat1", "true")
          return "Chat1.htm"
      elif n >= 4:
          return "Chat4.htm"
      return "Collected "+str(n)+" of 4 fangs"
    return
Если у игрока нет клыков (n=0), то мы получаем занчение переменной 'chat0'. Когда метод onKill вызван в первый раз, то пока ни каких переменных не имеется и python возвращает значение None. В этом случае объявляется переменная и показывается диалог Chat0.htm. Когда мы убиваем keltir, но не получаем с него клык, функция st.get('chat0') возвращает строку true, а не None. И во второй раз окно с Chat0.htm не появится, но в окне чата появится строчка «Collected 0 of 4 fangs». По тому же принципу сделано и с Chat1.htm.

Вот конечный рабочий вариант квеста:

Код:
import sys
from net.sf.l2j.gameserver.model.quest import State
from net.sf.l2j.gameserver.model.quest import QuestState
from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest


KELTIR_NPC_ID = 12082
FANGS_ITEM_ID = 1859
DROP_RATE     = 500000

WORLD_MAP_ITEM_ID = 1665


def getCount(st) :
  return st.getQuestItemsCount(FANGS_ITEM_ID)

def completed(st) :
  st.setState(COMPLETED)
  st.clearQuestDrops()
  st.takeItems(FANGS_ITEM_ID,-1)
  st.giveItems(WORLD_MAP_ITEM_ID,1)
  st.exitQuest(False)
  return

def check(st) :
  if getCount(st) >= 4 :
    completed(st)
  return

class Quest (JQuest):

  def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)

  def onEvent (self,event,st):
    id = st.getState()
    if   id == CREATED  : st.setState(STARTED)
    elif id == COMPLETED: pass
    elif id == STARTED  : check(st)
    return

  def onKill (self,npcId,st):
    if npcId == KELTIR_NPC_ID:
      n = getCount(st)
      if   n == 0:
        if st.get('chat0') == None :
          st.set("chat0", "true")
          return "Chat0.htm"
      elif n == 1:
        if st.get('chat1') == None :
          st.set("chat1", "true")
          return "Chat1.htm"
      elif n >= 4:
          return "Chat4.htm"
      return "Collect "+str(n)+" of 4 fangs"
    return

QUEST     = Quest(201, "Tutorial", "Tutorial quest")
CREATED   = State('Start',     QUEST)
STARTED   = State('Started',   QUEST)
COMPLETED = State('Completed', QUEST)

QUEST.setInitialState(CREATED)
QUEST.addStartNpc(7056)
QUEST.addStartNpc(7012)
QUEST.addStartNpc(7009)
QUEST.addStartNpc(7011)

STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,DROP_RATE)
STARTED.addKillId(KELTIR_NPC_ID)
STARTED.addTalkId(7056)
STARTED.addTalkId(7012)
STARTED.addTalkId(7009)
STARTED.addTalkId(7011)
Letov вне форума Ответить с цитированием
Сказали спасибо:
Непрочитано 14.09.2009, 15:55   #3
Пользователь

По умолчанию Ответ: мануал. Создание квестов

Я где - от в инете видел прогу которая сама создает квесты по заданным параметрам. Скажите свои мысли если кто такую встречал и успел опробовать.
fats вне форума Ответить с цитированием
Непрочитано 14.09.2009, 20:04   #4
™Diablo

По умолчанию Ответ: мануал. Создание квестов

Цитата:
Сообщение от fats Посмотреть сообщение
Я где - от в инете видел прогу которая сама создает квесты по заданным параметрам. Скажите свои мысли если кто такую встречал и успел опробовать.
Мне кажется, что лучше изучить мануал (пригодится), чем это все сделает какая-то программа. Согласитесь, что будете себя чувствовать уверение и приятнее.

P.S Это только мое мнение, может кто-то и не согласится
Zone-Game вне форума Отправить сообщение для Zone-Game с помощью ICQ Ответить с цитированием
Непрочитано 14.09.2009, 21:13   #5
Аватар для PROGRAMMATOR
Администратор

По умолчанию Ответ: мануал. Создание квестов

Почему не согласятся? Все согласятся! Программы, это хорошо, но вы же потом тот квест и поправить не сможете. Кстати, программа для написания квестов была написана для старых сборок, и как я понимаю давно не обновлялась, так как не была востребованной.
__________________
composer require laravel/framework
yarn add vue
PROGRAMMATOR вне форума Отправить сообщение для PROGRAMMATOR с помощью ICQ Отправить сообщение для PROGRAMMATOR с помощью Skype™ Ответить с цитированием
Непрочитано 23.11.2009, 07:34   #6
Аватар для ilbuono
Пользователь

По умолчанию Re: мануал. Создание квестов

Ребят,а есть совсем чайниковский мануал ? ато я чет прям сначала не понял как это делать) просто с явой дел не имел..с чего начинать то хоть?
ilbuono вне форума Отправить сообщение для ilbuono с помощью ICQ Ответить с цитированием
Непрочитано 28.05.2010, 12:18   #7
Аватар для Жужик
Пользователь

По умолчанию Re: мануал. Создание квестов

Цитата:
Сообщение от ilbuono Посмотреть сообщение
Ребят,а есть совсем чайниковский мануал ? ато я чет прям сначала не понял как это делать) просто с явой дел не имел..с чего начинать то хоть?
Полностью поддерживаю.... Я тоже мало что понял...
Подскажите:
Цитата:
Первое что нужно сделать, это добавить необходимые Java классы в квест. (net.sf.l2j.gameserver.model.quest).

Код:
import sys 
from net.sf.l2j.gameserver.model.quest import State 
from net.sf.l2j.gameserver.model.quest import QuestState 
from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest
где лежит файл net.sf.l2j.gameserver.model.quest
Жужик вне форума Ответить с цитированием
Непрочитано 31.05.2010, 23:52   #8
Аватар для VoltVolt
Пользователь

По умолчанию Re: мануал. Создание квестов

Вообще это не совсем файл. Т.е. по сути файл (с кодом) тут только "quest". Всё остальное - путь к нему.
В винде это выглядело бы так: net:\\sf\l2j\gameserver\model\quest
Ну и соответственно искать его в исходниках по этому "пути".

Но главное в том, что в этот файл тебе ничего добавлять не нужно. Ты просто ссылаешься на него и указываешь компилятору что из файла "quest" будут использоваться функции "State", "QuestState" и "QuestJython", иначе глупый компилятор не поймёт, откуда ты вызываешь эти функции и ничего не сможет собрать
__________________
Jedem das seine.
Каждому своё.
VoltVolt вне форума Ответить с цитированием
Непрочитано 16.11.2010, 23:34   #9
Новичок

По умолчанию Re: мануал. Создание квестов

Привет всем. Вот мучаюсь с такой проблемкой:
Создал квест по мануалу, вроде все как нада, но почему то в startGameServer.bat квест не загружается. А при разговоре с начальным НПЦ после нажатия "задание" он выдаёт I have no tasks for you right now.
Вот ссылка на мануал:
http://forum.doom55.ru/index.php?showtopic=50282

Мой квест:

  1.  
  2.  
  3. from net.sf.l2j.gameserver.model.quest import State
  4. from net.sf.l2j.gameserver.model.quest import QuestState
  5. from net.sf.l2j.gameserver.model.quest.jython import QuestJython as JQuest
  6.  
  7. class Quest (JQuest) :
  8.  
  9. def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr)
  10.  
  11. qn = "1001_Fool"
  12.  
  13. #NPC
  14. SINGAR = 100002
  15. # Items
  16. BOW = 14
  17. # Mobs
  18. DORFA = 100003
  19.  
  20. def onEvent (self,event,st) :
  21. htmltext = event
  22. cond = st.getInt("cond")
  23. if event == "100002-02.htm" :
  24. if cond == 0 :
  25. st.set("cond","1")
  26. st.setState(STARTED)
  27. st.playSound("ItemSound.quest_accept")
  28. return htmltext
  29.  
  30. def onTalk (self,npc,player):
  31. st = player.getQuestState(qn)
  32. htmltext = "<html><head><body>I have nothing to say you</body></html>"
  33. npcId = npc.getNpcId()
  34. if not st : return htmltext
  35. cond = st.getInt("cond")
  36. onlyone = st.getInt("onlyone")
  37. if npcId == SINGAR:
  38. htmltext = "100002-01.htm"
  39. return htmltext
  40. elif cond == 2 and st.getQuestItemsCount(BOW) >= 1 :
  41. st.takeItems(BOW,-1)
  42. st.set("cond","0")
  43. st.getPlayer().setNoble(True)
  44. st.giveItems(NOBLESS_TIARA,1)
  45. st.playSound("ItemSound.quest_finish")
  46. st.setState(COMPLETED)
  47. st.set("onlyone","1")
  48. htmltext = "100002-04.htm"
  49. if npcId == SINGAR:
  50. if cond == 0 and onlyone == 0 :
  51. if st.getPlayer().getLevel() >= 1 :
  52. htmltext = "100002-01.htm"
  53. else :
  54. htmltext = "100002-05.htm"
  55. st.exitQuest(1)
  56. elif cond == 1 and st.getQuestItemsCount(BOW) == 0 :
  57. htmltext = "100002-03.htm"
  58.  
  59. def onKill (self, npc, player) :
  60. st = player.getQuestState(qn)
  61. if not st : return
  62. if st.getState() != STARTED : return
  63. npcId = npc.getNpcId()
  64. cond = st.getInt("cond")
  65. if npcId == DORFA :
  66. if cond == 1 and st.getRandom(100)>70 :
  67. st.giveItems(BOW,1)
  68. st.playSound("ItemSound.quest_middle")
  69. st.set("cond","2")
  70. return
  71.  
  72. QUEST = Quest(1001,qn,"custom")
  73. CREATED = State('Start', QUEST)
  74. STARTED = State('Started', QUEST)
  75. COMPLETED = State('Completed', QUEST)
  76.  
  77. QUEST.setInitialState(CREATED)
  78. QUEST.addStartNpc(SINGAR)
  79. QUEST.addTalkId(SINGAR)
  80. QUEST.addKillId(DORFA)
  81. STARTED.addQuestDrop(DORFA,BOW ,1)
  82.  
Code: Python
Ссылка у нпц на квест тоже есть...

Последний раз редактировалось VISTALL; 17.11.2010 в 08:48. Причина: прикрасил
delvaness вне форума Ответить с цитированием
Непрочитано 31.12.2010, 01:13   #10
Новичок

По умолчанию Re: мануал. Создание квестов

Добавь путь к игишнику в script.grp
и добавь в аську 574055171
paulra вне форума Ответить с цитированием
Ответ


Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
 
Опции темы

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход


© 2007–2019 «Форум администраторов игровых серверов»
Защита сайта от DDoS атак — StormWall
Работает на Булке неизвестной версии с переводом от zCarot
Текущее время: 20:40. Часовой пояс GMT +3.

Вверх