local keywordHandler = KeywordHandler:new()
local npcHandler = NpcHandler:new(keywordHandler)
NpcSystem.parseParameters(npcHandler)
function onCreatureAppear(cid) npcHandler:onCreatureAppear(cid) end
function onCreatureDisappear(cid) npcHandler:onCreatureDisappear(cid) end
function onCreatureSay(cid, type, msg) npcHandler:onCreatureSay(cid, type, msg) end
function onThink() npcHandler:onThink() end
local randomGreeting = {
"Welcome back |PLAYERNAME|. Are you looking for a {task}?",
"How are you today |PLAYERNAME|? Ask me for a {task}.",
"Are you looking for a {task}, |PLAYERNAME|?"
}
local taskReplies = {}
local taskStorages = {45000, 45001, 45002, 45003} -- {task, choice, playerLevel, decision}
local tasks = {
--[[
Ensure that all tasks/choices/decisions are lowercase only. Do not use capitals.
{task = "task 1",
{choice = "choice 1",
{levelRange = {1, 9}, -- level 1 to 9
{decision = "decision 1",
deliveryDetails = {
{itemid = 1111, amount = 1}, -- will automatically fetch name of itemid
{itemid = 2222, amount = 2}
},
rewards = {
experience = 100,
money = 100, -- automatically converts to gold/plat/crystal
outfit = {outfitName = "name", looktypeMale = 111, looktypeFemale = 222},
addon = {outfitName = "name", looktypeMale = 111, looktypeFemale = 222, addon = 1}, -- addon 1 or 2 -> or 3 (both)
mount = {mountName = "name", mountId = 1},
items = {
{itemid = 1111, amount = {1, 1}}, -- amount = {minimum, maximum}
{itemid = 2222, amount = {2, 2}}
}
}
}
}
}
}
]]--
-- weapons
{task = "weapons",
{choice = "swords",
{levelRange = {1, 9},
{decision = "package one",
deliveryDetails = {
{itemid = 2403, amount = 3}, -- knife
{itemid = 2148, amount = 50} -- gold coins
},
rewards = {
experience = 1000000,
money = 10203, -- automatically converts to gold/plat/crystal
outfit = {outfitName = "noble", looktypeMale = 132, looktypeFemale = 140},
addon = {outfitName = "noble", looktypeMale = 132, looktypeFemale = 140, addon = 1}, -- addon 1 or 2 -> or 3 (both)
mount = {mountName = "widow queen", mountId = 1},
items = {
{itemid = 2461, amount = {1, 1}}, -- amount = {minimum, maximum}
{itemid = 2467, amount = {1, 1}},
{itemid = 2649, amount = {1, 1}},
{itemid = 2643, amount = {1, 1}},
{itemid = 2667, amount = {5, 10}}
}
}
},
{decision = "package two",
deliveryDetails = {
{itemid = 13829, amount = 2}
},
rewards = {
experience = 200 -- you can remove rewards from the list, to make it less cluttered
}
},
{decision = "package three",
deliveryDetails = {
{itemid = 2404, amount = 1}
},
rewards = {} -- if a task has no rewards, just leave it empty like this
}
},
{levelRange = {10, 30},
{decision = "package four",
deliveryDetails = {
{itemid = 2385, amount = 2}
},
rewards = {
experience = 100
}
},
{decision = "package five",
deliveryDetails = {
{itemid = 2395, amount = 1}
},
rewards = {
experience = 100
}
},
}
},
{choice = "axes",
{levelRange = {1, 9},
{decision = "decision 1",
deliveryDetails = {
{itemid = 1111, amount = 1}
},
rewards = {
experience = 100,
}
}
}
},
{choice = "clubs",
{levelRange = {1, 9},
{decision = "decision 1",
deliveryDetails = {
{itemid = 1111, amount = 1}
},
rewards = {
experience = 100,
}
}
}
},
{choice = "claws",
{levelRange = {1, 9},
{decision = "decision 1",
deliveryDetails = {
{itemid = 1111, amount = 1}
},
rewards = {
experience = 100,
}
}
}
},
{choice = "daggers",
{levelRange = {1, 9},
{decision = "decision 1",
deliveryDetails = {
{itemid = 1111, amount = 1}
},
rewards = {
experience = 100,
}
}
}
},
{choice = "bows",
{levelRange = {1, 9},
{decision = "decision 1",
deliveryDetails = {
{itemid = 1111, amount = 1}
},
rewards = {
experience = 100,
}
}
}
},
{choice = "crossbows",
{levelRange = {1, 9},
{decision = "decision 1",
deliveryDetails = {
{itemid = 1111, amount = 1}
},
rewards = {
experience = 100,
}
}
}
},
{choice = "guns",
{levelRange = {1, 9},
{decision = "decision 1",
deliveryDetails = {
{itemid = 1111, amount = 1}
},
rewards = {
experience = 100,
}
}
}
},
{choice = "wands",
{levelRange = {1, 9},
{decision = "decision 1",
deliveryDetails = {
{itemid = 1111, amount = 1}
},
rewards = {
experience = 100,
}
}
}
}
},
-- equipment
{task = "equipment",
{choice = "choice 1",
{levelRange = {1, 9},
{decision = "decision 1",
deliveryDetails = {
{itemid = 1111, amount = 1}
},
rewards = {
experience = 100,
}
}
}
}
},
-- supplies
{task = "supplies",
{choice = "choice 1",
{levelRange = {1, 9},
{decision = "decision 1",
deliveryDetails = {
{itemid = 1111, amount = 1}
},
rewards = {
experience = 100,
}
}
}
}
}
}
local function indexTask(msg)
local index = 0
for i = 1, #tasks do
if msg == tasks[i].task then
index = i
break
end
end
return index
end
local function indexChoice(cid, msg)
local index = 0
local task = tasks[taskReplies[cid].taskIndex]
for i = 1, #task do
if msg == task[i].choice then
index = i
break
end
end
return index
end
local function indexLevel(cid)
local index = 0
local task = tasks[taskReplies[cid].taskIndex][taskReplies[cid].choiceIndex]
local player = Player(cid)
local level = player:getLevel()
for i = 1, #task do
if level >= task[i].levelRange[1] and level <= task[i].levelRange[2] then
index = i
break
end
end
return index
end
local function indexDecision(cid, msg)
local index = 0
local task = tasks[taskReplies[cid].taskIndex][taskReplies[cid].choiceIndex][taskReplies[cid].levelIndex]
for i = 1, #task do
if msg == task[i].decision then
index = i
break
end
end
return index
end
local function listTasks()
local text = ""
for i = 1, #tasks do
if text ~= "" then
if #tasks == i then
text = text .. " or "
else
text = text .. ", "
end
end
text = text .. "{" .. tasks[i].task .. "}"
end
return text
end
local function listChoices(cid)
local text = ""
local task = tasks[taskReplies[cid].taskIndex]
for i = 1, #task do
if text ~= "" then
if #task == i then
text = text .. " or "
else
text = text .. ", "
end
end
text = text .. "{" .. task[i].choice .. "}"
end
return text
end
local function listDecisions(cid)
local text = ""
local task = tasks[taskReplies[cid].taskIndex][taskReplies[cid].choiceIndex][taskReplies[cid].levelIndex]
for i = 1, #task do
if text ~= "" then
if #task == i then
text = text .. " or "
else
text = text .. ", "
end
end
text = text .. "{" .. task[i].decision .. "}"
local delivery = task[i].deliveryDetails
local deliveryText = " ("
for n = 1, #delivery do
if deliveryText ~= " (" then
deliveryText = deliveryText .. ", "
end
deliveryText = deliveryText .. delivery[n].amount .. " " .. (delivery[n].amount == 1 and ItemType(delivery[n].itemid):getName() or ItemType(delivery[n].itemid):getPluralName())
end
text = text .. deliveryText .. ")"
end
return text
end
local function getChosenTaskDeliveryDetails(chosenTask)
local text = chosenTask.decision
local delivery = chosenTask.deliveryDetails
local deliveryText = " ("
for i = 1, #delivery do
if deliveryText ~= " (" then
deliveryText = deliveryText .. ", "
end
deliveryText = deliveryText .. delivery[i].amount .. " " .. (delivery[i].amount == 1 and ItemType(delivery[i].itemid):getName() or ItemType(delivery[i].itemid):getPluralName())
end
text = text .. deliveryText .. ")"
return text
end
local function findMissingDeliveryItems(cid, chosenTask)
local delivery = chosenTask.deliveryDetails
local missingItems = ""
local player = Player(cid)
for i = 1, #delivery do
if player:getItemCount(delivery[i].itemid) < delivery[i].amount then
if missingItems ~= "" then
missingItems = missingItems .. ", "
end
local missingAmount = delivery[i].amount - player:getItemCount(delivery[i].itemid)
missingItems = missingItems .. missingAmount .. " " .. (missingAmount == 1 and ItemType(delivery[i].itemid):getName() or ItemType(delivery[i].itemid):getPluralName())
end
end
return missingItems
end
local function removeDeliveryItems(cid, chosenTask)
local delivery = chosenTask.deliveryDetails
local player = Player(cid)
for i = 1, #delivery do
player:removeItem(delivery[i].itemid, delivery[i].amount)
end
return
end
local function deliverRewards(cid, chosenTask)
local text = ""
local rewardList = chosenTask.rewards
local player = Player(cid)
if rewardList.experience then
if text ~= "" then
text = text .. ", "
end
text = rewardList.experience .. " experience"
player:addExperience(rewardList.experience)
end
if rewardList.money then
if text ~= "" then
text = text .. ", "
end
text = text .. rewardList.money .. " gold coins"
player:addMoney(rewardList.money)
end
if rewardList.outfit then
if text ~= "" then
text = text .. ", "
end
text = text .. rewardList.outfit.outfitName .. " outfit"
player:addOutfit(rewardList.outfit.looktypeMale)
player:addOutfit(rewardList.outfit.looktypeFemale)
end
if rewardList.addon then
if text ~= "" then
text = text .. ", "
end
text = text .. (rewardList.addon.addon == 1 and "first" or rewardList.addon.addon == 2 and "second" or "first and second") .. " addon for the " .. rewardList.addon.outfitName .. " outfit"
player:addOutfitAddon(rewardList.addon.looktypeMale, rewardList.addon.addon)
player:addOutfitAddon(rewardList.addon.looktypeFemale, rewardList.addon.addon)
end
if rewardList.mount then
if text ~= "" then
text = text .. ", "
end
text = text .. rewardList.mount.mountName .. " mount"
player:addMount(rewardList.mount.mountId)
end
if rewardList.items then
rewardList = rewardList.items
local randAmount
for i = 1, #rewardList do
randAmount = math.random(rewardList[i].amount[1], rewardList[i].amount[2])
if randAmount > 0 then
if text ~= "" then
text = text .. ", "
end
text = text .. randAmount .. " " .. (randAmount == 1 and ItemType(rewardList[i].itemid):getName() or ItemType(rewardList[i].itemid):getPluralName())
player:addItem(rewardList[i].itemid, randAmount, true)
end
end
end
if text == "" then
text = "No reward for this task."
end
return text
end
local function greetCallback(cid)
npcHandler:setMessage(MESSAGE_GREET, randomGreeting[math.random(#randomGreeting)])
return true
end
local function creatureSayCallback(cid, type, msg)
if not npcHandler:isFocused(cid) then
return false
end
local player = Player(cid)
msg = msg:lower()
-- if no task started
if player:getStorageValue(taskStorages[1]) == -1 then
if msgcontains(msg, "task") then
npcHandler:say("Would you like to deliver " .. listTasks() .. "?", cid)
npcHandler.topic[cid] = 1
return true
elseif npcHandler.topic[cid] == 1 then
local taskIndex = indexTask(msg)
if taskIndex == 0 then
npcHandler:say("That's not on my list of items to deliver. Would you prefer to deliver " .. listTasks() .. "?", cid)
return true
end
taskReplies[cid].taskIndex = taskIndex
npcHandler:say("Would you like to deliver " .. listChoices(cid) .. "?", cid)
npcHandler.topic[cid] = 2
return true
elseif npcHandler.topic[cid] == 2 then
local choiceIndex = indexChoice(cid, msg)
if choiceIndex == 0 then
npcHandler:say("That's not on my list of items to deliver. Would you prefer to deliver " .. listChoices(cid) .. "?", cid)
return true
end
taskReplies[cid].choiceIndex = choiceIndex
local levelIndex = indexLevel(cid)
if levelIndex == 0 then
npcHandler:say("I don't have any " .. msg .. " that you can deliver at your current level. Try another option.", cid)
return true
end
taskReplies[cid].levelIndex = levelIndex
npcHandler:say("Would you like to deliver " .. listDecisions(cid) .. "?", cid)
npcHandler.topic[cid] = 3
return true
elseif npcHandler.topic[cid] == 3 then
local decisionIndex = indexDecision(cid, msg)
if decisionIndex == 0 then
npcHandler:say("That's not on my list of items to deliver. Would you prefer to deliver " .. listDecisions(cid) .. "?", cid)
return true
end
taskReplies[cid].decisionIndex = decisionIndex
npcHandler:say("Alright. Ask me about your {task} when you are ready to deliver.", cid)
player:setStorageValue(taskStorages[1], taskReplies[cid].taskIndex)
player:setStorageValue(taskStorages[2], taskReplies[cid].choiceIndex)
player:setStorageValue(taskStorages[3], taskReplies[cid].levelIndex)
player:setStorageValue(taskStorages[4], taskReplies[cid].decisionIndex)
taskReplies[cid] = {}
npcHandler.topic[cid] = 0
return true
end
-- if task started
else
local task = player:getStorageValue(taskStorages[1])
local choice = player:getStorageValue(taskStorages[2])
local level = player:getStorageValue(taskStorages[3])
local decision = player:getStorageValue(taskStorages[4])
local chosenTask = tasks[task][choice][level][decision]
if msgcontains(msg, "task") then
npcHandler:say("Do you want to {deliver} " .. chosenTask.decision .. ", {confirm} the delivery details or {cancel} the delivery task?", cid)
npcHandler.topic[cid] = 1
return true
elseif npcHandler.topic[cid] == 1 then
if msgcontains(msg, "cancel") then
npcHandler:say("Are you sure you want to cancel your task?", cid)
npcHandler.topic[cid] = 2
return true
end
if msgcontains(msg, "confirm") then
npcHandler:say("You need to deliver " .. getChosenTaskDeliveryDetails(chosenTask) .. ".", cid)
return true
end
if msgcontains(msg, "deliver") then
npcHandler:say("You are you ready to deliver " .. chosenTask.decision .. "?", cid)
npcHandler.topic[cid] = 3
return true
end
npcHandler:say("Sorry? Do you want to {deliver}, {confirm} or {cancel}?", cid)
return true
elseif npcHandler.topic[cid] == 2 then
if not msgcontains(msg, "yes") then
npcHandler:say("Whew! Thought you were going to quit on me! Let me know when you want to {deliver} your task.", cid)
npcHandler.topic[cid] = 1
return true
end
npcHandler:say("Alright. Your delivery task has been cancelled. You can choose a new {task} when you are ready.", cid)
player:setStorageValue(taskStorages[1], -1)
player:setStorageValue(taskStorages[2], -1)
player:setStorageValue(taskStorages[3], -1)
player:setStorageValue(taskStorages[4], -1)
npcHandler.topic[cid] = 0
elseif npcHandler.topic[cid] == 3 then
if not msgcontains(msg, "yes") then
npcHandler:say("Another time, then.", cid)
npcHandler.topic[cid] = 1
return true
end
local missingItems = findMissingDeliveryItems(cid, chosenTask)
if missingItems ~= "" then
npcHandler:say("You are missing some items for the delivery. (missing: " .. missingItems .. ") Let me know when you want to {deliver} your task.", cid)
npcHandler.topic[cid] = 1
return true
end
removeDeliveryItems(cid, chosenTask)
local rewardList = deliverRewards(cid, chosenTask)
npcHandler:say("Thanks for the quick delivery! Here's your compensation.\n(" .. rewardList .. ")\nYou can choose a new {task} when you are ready.", cid)
player:setStorageValue(taskStorages[1], -1)
player:setStorageValue(taskStorages[2], -1)
player:setStorageValue(taskStorages[3], -1)
player:setStorageValue(taskStorages[4], -1)
npcHandler.topic[cid] = 0
end
end
return true
end
local function onAddFocus(cid)
npcHandler.topic[cid] = 0
taskReplies[cid] = {}
end
local function onReleaseFocus(cid)
npcHandler.topic[cid] = 0
taskReplies[cid] = {}
end
npcHandler:setCallback(CALLBACK_ONADDFOCUS, onAddFocus)
npcHandler:setCallback(CALLBACK_ONRELEASEFOCUS, onReleaseFocus)
npcHandler:setCallback(CALLBACK_GREET, greetCallback)
npcHandler:setCallback(CALLBACK_MESSAGE_DEFAULT, creatureSayCallback)
npcHandler:addModule(FocusModule:new())