Вот мануал по квестописанию
8 replies243 viewsCurrently viewing: 1
· 10/04/2009, 03:59 AM
Цитата
первое что нужно сделать, это добавить необходимые 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
Класс QuestJython (импортирован под названием JQuest) содержит информацию о квестах.
Класс State используется для того, что бы описать информацию о состоянии квеста.
Класс QuestState применяется непосредственно для отслеживания состояния игрока, о ходе выполнения квеста или части квеста.
Затем необходимо добавить несколько констант, что сделает квест удобочитаемым. Если этого не сделать, то могут возникнуть сложности с редактированием квеста в будущем.
Константы нашего квеста – это ID NCP и итемов.
Код
KELTIR_NPC_ID = 12082
FANGS_ITEM_ID = 1859
DROP_RATE = 500000
WORLD_MAP_ITEM_ID = 1665
Затем объявите несколько вспомогательных функций.
Функция для получения количества квестовых предметов (keltir fangs) у игрока. (st должна быть в QuestState):
Код
def getCount(st) :
return st.getQuestItemsCount(FANGS_ITEM_ID)
Функция для завершения квеста (st должна быть в QuestState):
Код
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):
Код
def check(st) :
if getCount(st) >= 4 :
completed(st)
return
Затем мы объявляем непосредственно сам класс quest. Quest – класс python, который расширяет java класс net.sf.l2j.gameserver.model.quest.jython.QuestJyth on. Затем мы объявляем метод onEvent, который вызывается Явой, если квест кто то начал.
Код
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
Метод 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.
И наконец, когда скелет квеста определен, мы создаем сам квест (и определяем его в самом сервере) и объявляем его.
Код
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.
Код
QUEST.setInitialState(CREATED)
QUEST.addStartNpc(7056)
Обратите внимание: в файле htm стартового NCP обязательно должна быть ссылка на квест:
Код
<a action="bypass -h npc_%objectId%_Quest">
Теперь необходимо добавить дроп для этого квеста при состоянии STARTED, для того, что бы получить необходимые вещи.
Код
STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,D ROP_RATE)
Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста:
Код
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
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,D ROP_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:
Код
STARTED.addKillId(KELTIR_NPC_ID)
и метод onKill в классе Quest:
class Quest (JQuest):
...
def onKill (self,npcId,st):
if npcId == KELTIR_NPC_ID:
n = getCount(st)
if n == 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 с текстом, который стоит далее. Так вместо:
Код
return "Chat4.htm"
можно поставить:
Код
return "<html><body>Return to your trainer to complete the quest</body></html>"
Так же если строка заканчивается без .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,D ROP_RATE)
STARTED.addKillId(KELTIR_NPC_ID)
STARTED.addTalkId(7056)
STARTED.addTalkId(7012)
STARTED.addTalkId(7009)
STARTED.addTalkId(7011)
Код
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 и итемов.
Код
KELTIR_NPC_ID = 12082
FANGS_ITEM_ID = 1859
DROP_RATE = 500000
WORLD_MAP_ITEM_ID = 1665
Затем объявите несколько вспомогательных функций.
Функция для получения количества квестовых предметов (keltir fangs) у игрока. (st должна быть в QuestState):
Код
def getCount(st) :
return st.getQuestItemsCount(FANGS_ITEM_ID)
Функция для завершения квеста (st должна быть в QuestState):
Код
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):
Код
def check(st) :
if getCount(st) >= 4 :
completed(st)
return
Затем мы объявляем непосредственно сам класс quest. Quest – класс python, который расширяет java класс net.sf.l2j.gameserver.model.quest.jython.QuestJyth on. Затем мы объявляем метод onEvent, который вызывается Явой, если квест кто то начал.
Код
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
Метод 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.
И наконец, когда скелет квеста определен, мы создаем сам квест (и определяем его в самом сервере) и объявляем его.
Код
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.
Код
QUEST.setInitialState(CREATED)
QUEST.addStartNpc(7056)
Обратите внимание: в файле htm стартового NCP обязательно должна быть ссылка на квест:
Код
<a action="bypass -h npc_%objectId%_Quest">
Теперь необходимо добавить дроп для этого квеста при состоянии STARTED, для того, что бы получить необходимые вещи.
Код
STARTED.addQuestDrop(KELTIR_NPC_ID,FANGS_ITEM_ID,D ROP_RATE)
Для этого квеста больше ничего не надо. Все необходимое для корректной работы квеста уже добавили. Вот полный текст квеста:
Код
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
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,D ROP_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:
Код
STARTED.addKillId(KELTIR_NPC_ID)
и метод onKill в классе Quest:
class Quest (JQuest):
...
def onKill (self,npcId,st):
if npcId == KELTIR_NPC_ID:
n = getCount(st)
if n == 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 с текстом, который стоит далее. Так вместо:
Код
return "Chat4.htm"
можно поставить:
Код
return "<html><body>Return to your trainer to complete the quest</body></html>"
Так же если строка заканчивается без .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,D ROP_RATE)
STARTED.addKillId(KELTIR_NPC_ID)
STARTED.addTalkId(7056)
STARTED.addTalkId(7012)
STARTED.addTalkId(7009)
STARTED.addTalkId(7011)
Все связанне с серверами могу помочь. Пишите в ПМ если что
0
· 10/04/2009, 04:27 AM
http://la2base.ru/forum/index.php?showtopic=13388
Тему в мусорку, а автору в поиск.
You can't feeling! No you can't feeling! And you can't feeling!
— People = Shit
0
· 10/04/2009, 04:59 AM
Значить извиняюсь!:)
Все связанне с серверами могу помочь. Пишите в ПМ если что
0
· 10/04/2009, 05:35 AM
А вот по написанию рецепта ненашёл у Вас.
Цитата
1. Идем в папку gameserver\data\ и ищем там файл recipes.csv
2. Открываем его и видем что-то странное, честно говоря сам не понял что=), но нам на это пох, мы идем в самый низ.
3. В самый конец вписываем вот это :
dwarven;mk_new_item;844;9991;9;[9650(1)],[5553(1)];57;20000000;[9650(1)],[57(540
000)];225;100;
Сейчас сделаем лиричиское отступление, и я расскажу какое значение за что отвечает:
-dwarven - означает то, что рецепт могу открыть только гнумы, можно поставить значение common, в таком случаем рецепт откроют все.
-mk_new_item - название итема. Состоит из : mk_ - обязательный префикс, значение для крафта, и new_item, ваш предмет, можно без
низжней черы, если одно слово.
- 844 - ID рецепта в скрипте, в моей сборке последним был рецепт с идом 843, по этому я взял 844.
- 9991 - ID рецепта по базе данных MySQL, тоесть тот ID, который мы будем спавнить как итем или кидать в мультиселл.
- 9 - необходимый уровень крафт скила(не забываем, если ставить возможность всем открывать и крафтить рецепт, то ставим уровень 1).
- [9650(1)],[5553(1)];57;20000000;[9650(1)] - вещи необходимые для крафта итема ([ID предмета(количество)],...)
- [57(100000000)] - то, что мы собираемся крафтить, в нашем случае 100кк аден.
- 225 - это значение регулирует сколько маны мы угробим...
- 100 - шанс того, что крафт пройдет успешен.
4. На основе вышенаписанного создаем свой рецепт.
5. Теперь нужно добавить наш запрос в сервер, тоесть делаем запрос в базу данных MySQL:
INSERT INTO `etcitem`
(`item_id`,`name`,`crystallizable`,`item_type`,`weight`,`consume_type`,`material`,`crystal_type`,
`duration`,`price`,`crystal_count`,`sellable`,`dropable`,`
destroyable`,`tradeable`,`oldname`,`oldtype`) VALUES
('9991','Recipe: 100kk Adena','false','recipe','30','stackable','liquid','none','-1','0','0','true','true','true','true','mk_new_item','recipe');
-Первая строчка является пояснением к значениям, темболее некоторые их них мы разбирали чуток выше, по этому останавливаться не будем.
6. Запускаем File Edit и открываем файл itemname-e.dat который лежит в папка клиента/system/
7. В самый конец добовляем:
9991 Recipe: 100kk Adena. Требуется 9 уровень создания вещей. Шанс создания вещи - 100%. -1 0 0 0
-Изменяем все под себя и не забываем в конце остваить одну пустую строчку.
8. Открываем etcitemgrp.dat, находим любой рецепт, вставляем его в самый конец, меняем ID, название и в конце оставляем одну пустую строчку.
9. Но и этого не достаточно. Идем в файл recipe-c.dat.
10. Точно так же копируем любую строку и вставляем в конце, но вот тут то и вся муть - надо соблюдать все пропорции,ничего лишнего
ненаудалять и непонаписать, иначе он просто обратно не закодирует - будет ошибку выдавать.
- Вот мы нашли нашли рецепт, подробно разбирем что для чего:
mk_eye_of_soul_ii(имя рецетпа, лучше указывать в соответсвии с пунктом 3.2) 805(id рецепта по файлу рецептов) 8313(id рецепта по бд) 7(лвл крафта) 7894(что
производиться) 1(сколько) 192(сколько маны надо) 100(шанс) 10(сколько вещей учавсвует в крафте) 8313(что надо для крафта) 1(сколько) 8341(что надо для
крафта) 13(сколько) 5554(и так далее) 2 1890 122 1888 122 1885 61 4042 61 5550 244 1460 415 2132 143
- К нашему рецепту выйдет вот такая вот штукенция:
mk_new_item 844 9991 9 57 100000000 225 100 2 5553 1 9650 1
Если вы все сделали правильно, то после рестарта(лучше делать при выключенном сервере), или при его включении, появится ваш собственный рецепт.
2. Открываем его и видем что-то странное, честно говоря сам не понял что=), но нам на это пох, мы идем в самый низ.
3. В самый конец вписываем вот это :
dwarven;mk_new_item;844;9991;9;[9650(1)],[5553(1)];57;20000000;[9650(1)],[57(540
000)];225;100;
Сейчас сделаем лиричиское отступление, и я расскажу какое значение за что отвечает:
-dwarven - означает то, что рецепт могу открыть только гнумы, можно поставить значение common, в таком случаем рецепт откроют все.
-mk_new_item - название итема. Состоит из : mk_ - обязательный префикс, значение для крафта, и new_item, ваш предмет, можно без
низжней черы, если одно слово.
- 844 - ID рецепта в скрипте, в моей сборке последним был рецепт с идом 843, по этому я взял 844.
- 9991 - ID рецепта по базе данных MySQL, тоесть тот ID, который мы будем спавнить как итем или кидать в мультиселл.
- 9 - необходимый уровень крафт скила(не забываем, если ставить возможность всем открывать и крафтить рецепт, то ставим уровень 1).
- [9650(1)],[5553(1)];57;20000000;[9650(1)] - вещи необходимые для крафта итема ([ID предмета(количество)],...)
- [57(100000000)] - то, что мы собираемся крафтить, в нашем случае 100кк аден.
- 225 - это значение регулирует сколько маны мы угробим...
- 100 - шанс того, что крафт пройдет успешен.
4. На основе вышенаписанного создаем свой рецепт.
5. Теперь нужно добавить наш запрос в сервер, тоесть делаем запрос в базу данных MySQL:
INSERT INTO `etcitem`
(`item_id`,`name`,`crystallizable`,`item_type`,`weight`,`consume_type`,`material`,`crystal_type`,
`duration`,`price`,`crystal_count`,`sellable`,`dropable`,`
destroyable`,`tradeable`,`oldname`,`oldtype`) VALUES
('9991','Recipe: 100kk Adena','false','recipe','30','stackable','liquid','none','-1','0','0','true','true','true','true','mk_new_item','recipe');
-Первая строчка является пояснением к значениям, темболее некоторые их них мы разбирали чуток выше, по этому останавливаться не будем.
6. Запускаем File Edit и открываем файл itemname-e.dat который лежит в папка клиента/system/
7. В самый конец добовляем:
9991 Recipe: 100kk Adena. Требуется 9 уровень создания вещей. Шанс создания вещи - 100%. -1 0 0 0
-Изменяем все под себя и не забываем в конце остваить одну пустую строчку.
8. Открываем etcitemgrp.dat, находим любой рецепт, вставляем его в самый конец, меняем ID, название и в конце оставляем одну пустую строчку.
9. Но и этого не достаточно. Идем в файл recipe-c.dat.
10. Точно так же копируем любую строку и вставляем в конце, но вот тут то и вся муть - надо соблюдать все пропорции,ничего лишнего
ненаудалять и непонаписать, иначе он просто обратно не закодирует - будет ошибку выдавать.
- Вот мы нашли нашли рецепт, подробно разбирем что для чего:
mk_eye_of_soul_ii(имя рецетпа, лучше указывать в соответсвии с пунктом 3.2) 805(id рецепта по файлу рецептов) 8313(id рецепта по бд) 7(лвл крафта) 7894(что
производиться) 1(сколько) 192(сколько маны надо) 100(шанс) 10(сколько вещей учавсвует в крафте) 8313(что надо для крафта) 1(сколько) 8341(что надо для
крафта) 13(сколько) 5554(и так далее) 2 1890 122 1888 122 1885 61 4042 61 5550 244 1460 415 2132 143
- К нашему рецепту выйдет вот такая вот штукенция:
mk_new_item 844 9991 9 57 100000000 225 100 2 5553 1 9650 1
Если вы все сделали правильно, то после рестарта(лучше делать при выключенном сервере), или при его включении, появится ваш собственный рецепт.
Все связанне с серверами могу помочь. Пишите в ПМ если что
0
· 10/04/2009, 05:09 PM
MrArt: А вот по написанию рецепта ненашёл у Вас.
Мдас... таким кадром ещё нужно быть...
К чему катится мир??? когда народ осознано копипастит и не скрывает этого? вы бы хоть прикинулись "дурачком"...
0
· 10/04/2009, 05:41 PM
Цитата
Мдас... таким кадром ещё нужно быть...
К чему катится мир??? когда народ осознано копипастит и не скрывает этого? вы бы хоть прикинулись "дурачком"...
К чему катится мир??? когда народ осознано копипастит и не скрывает этого? вы бы хоть прикинулись "дурачком"...
Я же не во зло это делаю, а в помощь народу!:)
Все связанне с серверами могу помочь. Пишите в ПМ если что
0
· 10/05/2009, 11:00 AM
MrArt: Я же не во зло это делаю, а в помощь народу!:)
Это смотря с какой стороны, для пользователей кучу мануала это приятно но куча повтора... это искать иголку в стогу сена... Так что тут и плюс и минус. а вот для администрации только минусы... Надо за всем следить, и дулаять... + база данных не резиновая... всему есть придел...
0
Войдите или зарегистрируйтесь чтобы ответить



