Добавить в корзинуПозвонить
Найти в Дзене

«Lua для TFS: пишем первый скрипт на обработку событий (на примере системы квестов)».

Оглавление

Lua для TFS: пишем первый скрипт на обработку событий (на примере системы квестов)

Разберём создание простой системы квестов для TFS (The Forgotten Server) на Lua — от базовой структуры до обработки событий.

Шаг 1. Структура данных квеста

Создадим таблицу с описанием квеста:

lua

quests = {
[1] = {
name = "Охота на гоблинов",
description = "Убейте 5 гоблинов и доложите старосте.",
target_mob = "goblin",
target_count = 5,
reward_exp = 1000,
reward_items = {{id = 2148, count = 10}}, -- 10 золотых монет
started = false,
progress = 0
}
}

Шаг 2. Регистрация обработчиков событий

В TFS события регистрируются через registerCreatureEvent(). Добавим обработчики:

lua

-- Регистрация событий для игрока
Player:registerEvent("QuestStart")
Player:registerEvent("QuestKill")
Player:registerEvent("QuestComplete")

Шаг 3. Скрипт квеста (quests.lua)

Поместим скрипт в папку data/scripts/.

1. Функция начала квеста:

lua

function onQuestStart(player, item, fromPosition, target, toPosition, isHotkey)
local questId = 1 -- ID квеста
local quest = quests[questId]

if not quest.started then
quest.started = true
player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Квест начат: " .. quest.name)
player:setStorageValue(questId, 1) -- сохраняем прогресс
else
player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Вы уже выполняете этот квест!")
end
return true
end

2. Обработчик убийства моба:

lua

function onKill(creature, target)
if not creature:isPlayer() then return true end

local player = creature
local targetName = target:getName():lower()
local questId = 1
local quest = quests[questId]

-- Проверяем, что игрок выполняет квест и убил нужного моба
if quest.started and quest.target_mob == targetName then
quest.progress = quest.progress + 1
player:sendTextMessage(MESSAGE_EVENT_ADVANCE,
"Прогресс квеста: " .. quest.progress .. "/" .. quest.target_count)

-- Сохраняем прогресс в хранилище игрока
player:setStorageValue(questId + 1000, quest.progress)

-- Проверяем завершение квеста
if quest.progress >= quest.target_count then
player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Квест завершён! Заберите награду у старосты.")
end
end
return true
end

3. Функция получения награды:

lua

function onQuestComplete(player, item, fromPosition, target, toPosition, isHotkey)
local questId = 1
local quest = quests[questId]

if quest.progress >= quest.target_count and quest.started then
-- Выдаём награду
player:addExperience(quest.reward_exp)
for _, reward in ipairs(quest.reward_items) do
player:addItem(reward.id, reward.count)
end

-- Сбрасываем прогресс
quest.started = false
quest.progress = 0
player:setStorageValue(questId, -1)
player:setStorageValue(questId + 1000, 0)

player:sendTextMessage(MESSAGE_EVENT_ADVANCE,
"Награда получена: " .. quest.reward_exp .. " опыта и предметы!")
else
player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Вы ещё не выполнили условия квеста!")
end
return true
end

Шаг 4. Конфигурация событий (creatureevents.xml)

Добавьте в data/creatureevents/creatureevents.xml:

xml

<event type="login" name="QuestStart" script="quests.lua"/>
<event type="kill" name="QuestKill" script="quests.lua"/>
<event type="usecontainer" name="QuestComplete" script="quests.lua"/>

Шаг 5. Интеграция с NPC

Чтобы игрок мог начать квест у NPC, отредактируйте скрипт NPC:

lua

local keywordHandler = KeywordHandler:new()
local npcHandler = NpcHandler:new(keywordHandler)
NpcSystem.parseParameters(npcHandler)

function creatureSayCallback(cid, type, msg)
if not npcHandler:isFocused(cid) then return false end

local player = Player(cid)
if msgcontains(msg, "quest") then
npcHandler:say("Хотите взять квест 'Охота на гоблинов'?", cid)
npcHandler.topic[cid] = 1
elseif npcHandler.topic[cid] == 1 then
if msgcontains(msg, "yes") then
-- Вызываем функцию начала квеста
onQuestStart(player)
npcHandler:say("Удачи в выполнении!", cid)
else
npcHandler:say("Приходите, когда будете готовы.", cid)
end
npcHandler.topic[cid] = 0
end
return true
end

npcHandler.setCallback(CALLBACK_MESSAGE_DEFAULT, creatureSayCallback)
npcHandler.addModule(FocusModule:new())

Шаг 6. Тестирование

  1. Запустите сервер.
  2. Поговорите с NPC и возьмите квест.
  3. Убейте 5 гоблинов.
  4. Вернитесь к NPC и получите награду.
  5. Проверьте логи на ошибки: tail -f logs/game.log.

Дополнительные возможности

Расширение системы:

  • Несколько квестов: добавьте больше записей в таблицу quests.
  • Условия старта: проверяйте уровень игрока (player:getLevel()) или другие квесты.
  • Промежуточные цели: сохраняйте прогресс для каждого этапа квеста.
  • Таймеры: используйте addEvent() для ограниченных по времени квестов.
  • Визуальные эффекты: добавляйте анимации при получении награды (player:sendMagicEffect(CONST_EFFECT_EXPLOSION)).

Отладка:

  • Используйте print() для вывода отладочной информации в консоль сервера.
  • Проверяйте значения storage через player:getStorageValue().
  • Логируйте ошибки в файл: io.write("Ошибка квеста: " .. err .. "\n").

Чек‑лист проверки

  1. Квест запускается через NPC.
  2. Прогресс убийства мобов сохраняется.
  3. Награда выдаётся при выполнении условий.
  4. Данные квеста сохраняются между перезагрузками сервера.
  5. Ошибки не выводятся в логах.

Устранение распространённых проблем

  • «Квест не начинается»: проверьте регистрацию события в creatureevents.xml.
  • «Прогресс не сохраняется»: убедитесь, что setStorageValue() вызывается с уникальными ID.
  • «Награда не выдаётся»: проверьте условие if quest.progress >= quest.target_count.
  • «Ошибки в скрипте»: проверьте синтаксис Lua и соответствие имён функций в XML.

Теперь у вас есть основа для создания сложных квестовых систем в TFS. Если хотите, могу помочь расширить функционал или разобрать другой тип событий!