• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

Lua Certain NPC won't load.

Scuss21

New Member
Joined
Jan 19, 2009
Messages
37
Reaction score
1
HTML:
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 voices = { {text = 'Nothing beats the feeling of flying with a carpet!'} }
npcHandler:addModule(VoiceModule:new(voices))
local function creatureSayCallback(cid, type, msg)
 if not npcHandler:isFocused(cid) then
  return false
 end
 local player = Player(cid)
 if msgcontains(msg, 'ticket') then
  if player:getStorageValue(Storage.wagonTicket) >= os.time() then
   npcHandler:say('Your weekly ticket is still valid. Would be a waste of money to purchase a second one', cid)
   return true
  end
  npcHandler:say('Do you want to purchase a weekly ticket for the ore wagons? With it you can travel freely and swiftly through Kazordoon for one week. 250 gold only. Deal?', cid)
  npcHandler.topic[cid] = 1
 elseif npcHandler.topic[cid] == 1 then
  if msgcontains(msg, 'yes') then
   if not player:removeMoney(250) then
    npcHandler:say('You don\'t have enough money.', cid)
    return true
   end
   player:setStorageValue(Storage.wagonTicket, os.time() + 7 * 24 * 60 * 60)
   npcHandler:say('Here is your stamp. It can\'t be transferred to another person and will last one week from now. You\'ll get notified upon using an ore wagon when it isn\'t valid anymore.', cid)
  elseif msgcontains(msg, 'no') then
   npcHandler:say('No then.', cid)
  end
  npcHandler.topic[cid] = 0
 end
 return true
end
-- Travel
local function addTravelKeyword(keyword, text, cost, destination)
 if keyword == 'farmine' then
  keywordHandler:addKeyword({keyword}, StdModule.say, {npcHandler = npcHandler, text = 'Never heard about a place like this.'}, function(player) return player:getStorageValue(Storage.TheNewFrontier.Mission10) ~= 1 end)
 end
 local travelKeyword = keywordHandler:addKeyword({keyword}, StdModule.say, {npcHandler = npcHandler, text = 'Do you seek a ride to ' .. text .. ' for |TRAVELCOST|?', cost = cost, discount = 'postman'})
  travelKeyword:addChildKeyword({'yes'}, StdModule.travel, {npcHandler = npcHandler, premium = true, text = 'Hold on!', cost = cost, discount = 'postman', destination = destination})
  travelKeyword:addChildKeyword({'no'}, StdModule.say, {npcHandler = npcHandler, text = 'You shouldn\'t miss the experience.', reset = true})
end
addTravelKeyword('farmine', 'Farmine', 60, Position(32983, 31539, 1))
addTravelKeyword('darashia', 'Darashia on Darama', 40, Position(33270, 32441, 6))
addTravelKeyword('svargrond', 'Svargrond', 60, Position(32253, 31097, 4))
addTravelKeyword('femor hills', 'the Femor Hills', 40, Position(32536, 31837, 4))
addTravelKeyword('edron', 'Edron', 60, Position(33193, 31784, 3))
npcHandler:setMessage(MESSAGE_GREET, "Greetings, traveller |PLAYERNAME|. Where do you want me to {fly} you? Or do you need a weekly ticket for the Kazordoon public lorry transport?")
npcHandler:setMessage(MESSAGE_FAREWELL, "Good bye!")
npcHandler:setMessage(MESSAGE_WALKAWAY, "Good bye!")
npcHandler:setCallback(CALLBACK_MESSAGE_DEFAULT, creatureSayCallback)
npcHandler:addModule(FocusModule:new())

Just like the post says I'm having a little bit of a problem with this.

data/npc/scripts/Gewen.lua:11: attempt to index global 'VoiceModule' (a nil value)

Is it voices that's wrong? A lot of the other NPC I have, has the same value.
 
Solution
you are missing certain lib scripts

In npc\lib\npcsystem\customModules.lua

At the end of the file add following:

Lua:
-- VoiceModule
VoiceModule = {
   voices = nil,
   voiceCount = 0,
   lastVoice = 0,
   timeout = nil,
   chance = nil,
   npcHandler = nil
}

-- Creates a new instance of VoiceModule
function VoiceModule:new(voices, timeout, chance)
   local obj = {}
   setmetatable(obj, self)
   self.__index = self

   obj.voices = voices
   for i = 1, #obj.voices do
       if obj.voices[i].yell then
           obj.voices[i].yell = nil
           obj.voices[i].talktype = TALKTYPE_YELL
       else
           obj.voices[i].talktype = TALKTYPE_SAY
       end
   end

   obj.voiceCount = #voices
   obj.timeout = timeout or 10...
you are missing certain lib scripts

In npc\lib\npcsystem\customModules.lua

At the end of the file add following:

Lua:
-- VoiceModule
VoiceModule = {
   voices = nil,
   voiceCount = 0,
   lastVoice = 0,
   timeout = nil,
   chance = nil,
   npcHandler = nil
}

-- Creates a new instance of VoiceModule
function VoiceModule:new(voices, timeout, chance)
   local obj = {}
   setmetatable(obj, self)
   self.__index = self

   obj.voices = voices
   for i = 1, #obj.voices do
       if obj.voices[i].yell then
           obj.voices[i].yell = nil
           obj.voices[i].talktype = TALKTYPE_YELL
       else
           obj.voices[i].talktype = TALKTYPE_SAY
       end
   end

   obj.voiceCount = #voices
   obj.timeout = timeout or 10
   obj.chance = chance or 25
   return obj
end

function VoiceModule:init(handler)
   return true
end

function VoiceModule:callbackOnThink()
   if self.lastVoice < os.time() then
       self.lastVoice = os.time() + self.timeout
       if math.random(100) < self.chance  then
           local voice = self.voices[math.random(self.voiceCount)]
           Npc():say(voice.text, voice.talktype)
       end
   end
   return true
end


if you do not have customModules.lua create one called called voiceModule.lua and paste in that code; Then edit /npc/lib/npc.lua

and add this at the top of the file

Lua:
dofile('data/npc/lib/npcsystem/voiceModule.lua')
 
Solution
you are missing certain lib scripts

In npc\lib\npcsystem\customModules.lua

At the end of the file add following:

Lua:
-- VoiceModule
VoiceModule = {
   voices = nil,
   voiceCount = 0,
   lastVoice = 0,
   timeout = nil,
   chance = nil,
   npcHandler = nil
}

-- Creates a new instance of VoiceModule
function VoiceModule:new(voices, timeout, chance)
   local obj = {}
   setmetatable(obj, self)
   self.__index = self

   obj.voices = voices
   for i = 1, #obj.voices do
       if obj.voices[i].yell then
           obj.voices[i].yell = nil
           obj.voices[i].talktype = TALKTYPE_YELL
       else
           obj.voices[i].talktype = TALKTYPE_SAY
       end
   end

   obj.voiceCount = #voices
   obj.timeout = timeout or 10
   obj.chance = chance or 25
   return obj
end

function VoiceModule:init(handler)
   return true
end

function VoiceModule:callbackOnThink()
   if self.lastVoice < os.time() then
       self.lastVoice = os.time() + self.timeout
       if math.random(100) < self.chance  then
           local voice = self.voices[math.random(self.voiceCount)]
           Npc():say(voice.text, voice.talktype)
       end
   end
   return true
end


if you do not have customModules.lua create one called called voiceModule.lua and paste in that code; Then edit /npc/lib/npc.lua

and add this at the top of the file

Lua:
dofile('data/npc/lib/npcsystem/voiceModule.lua')

I already have that in my customModule.lua file, I even redid it with the one you just posted and still nothing.
Maybe my npc.lua file is not recognizing it?

Lua:
dofile('data/npc/lib/npcsystem/npcsystem.lua')
function msgcontains(message, keyword)
 local message, keyword = message:lower(), keyword:lower()
 if message == keyword then
  return true
 end
 return message:find(keyword) and not message:find('(%w+)' .. keyword)
end
function doNpcSellItem(cid, itemid, amount, subType, ignoreCap, inBackpacks, backpack)
 local amount = amount or 1
 local subType = subType or 0
 local item = 0
 if isItemStackable(itemid) then
  if inBackpacks then
   stuff = doCreateItemEx(backpack, 1)
   item = doAddContainerItem(stuff, itemid, math.min(100, amount))
  else
   stuff = doCreateItemEx(itemid, math.min(100, amount))
  end
  return doPlayerAddItemEx(cid, stuff, ignoreCap) ~= RETURNVALUE_NOERROR and 0 or amount, 0
 end
 local a = 0
 if inBackpacks then
  local container, b = doCreateItemEx(backpack, 1), 1
  for i = 1, amount do
   local item = doAddContainerItem(container, itemid, subType)
   if table.contains({(getContainerCapById(backpack) * b), amount}, i) then
    if doPlayerAddItemEx(cid, container, ignoreCap) ~= RETURNVALUE_NOERROR then
     b = b - 1
     break
    end
    a = i
    if amount > i then
     container = doCreateItemEx(backpack, 1)
     b = b + 1
    end
   end
  end
  return a, b
 end
 for i = 1, amount do -- normal method for non-stackable items
  local item = doCreateItemEx(itemid, subType)
  if doPlayerAddItemEx(cid, item, ignoreCap) ~= RETURNVALUE_NOERROR then
   break
  end
  a = i
 end
 return a, 0
end
local func = function(cid, text, type, e, pcid)
 if isPlayer(pcid) then
  doCreatureSay(cid, text, type, false, pcid, getCreaturePosition(cid))
  e.done = TRUE
 end
end
function doCreatureSayWithDelay(cid, text, type, delay, e, pcid)
 if isPlayer(pcid) then
  e.done = FALSE
  e.event = addEvent(func, delay < 1 and 1000 or delay, cid, text, type, e, pcid)
 end
end
function doPlayerTakeItem(cid, itemid, count)
 if getPlayerItemCount(cid,itemid) < count then
  return false
 end
 while count > 0 do
  local tempcount = 0
  if isItemStackable(itemid) then
   tempcount = math.min (100, count)
  else
   tempcount = 1
  end
  local ret = doPlayerRemoveItem(cid, itemid, tempcount)
  if ret ~= false then
   count = count - tempcount
  else
   return false
  end
 end
 if count ~= 0 then
  return false
 end
 return true
end
function doPlayerSellItem(cid, itemid, count, cost)
 if doPlayerTakeItem(cid, itemid, count) == true then
  if not doPlayerAddMoney(cid, cost) then
   error('Could not add money to ' .. getPlayerName(cid) .. '(' .. cost .. 'gp)')
  end
  return true
 end
 return false
end
function doPlayerBuyItemContainer(cid, containerid, itemid, count, cost, charges)
 if not doPlayerRemoveMoney(cid, cost) then
  return false
 end
 for i = 1, count do
  local container = doCreateItemEx(containerid, 1)
  for x = 1, getContainerCapById(containerid) do
   doAddContainerItem(container, itemid, charges)
  end
  if doPlayerAddItemEx(cid, container, true) ~= RETURNVALUE_NOERROR then
   return false
  end
 end
 return true
end
function getCount(string)
 local b, e = string:find("%d+")
 return b and e and tonumber(string:sub(b, e)) or -1
end
 
its not specified in your npc.lua

add this on 3rd line.
dofile('data/npc/lib/npcsystem/customModules.lua')

under your other dofile.
 
its not specified in your npc.lua

add this on 3rd line.
dofile('data/npc/lib/npcsystem/customModules.lua')

under your other dofile.

That worked but now I'm getting a new error message with my customModules.lua file.

data/npc/lib/npcsystem/custommodules.lua:3: attempt to index global 'Storage' (a nil value)
stack traceback:
[C]: in function '__index'
[C] in function 'dofile'

Lua:
 ['postman'] = {price = 10, storage = Storage.postman.Rank, value = 3},
 ['new frontier'] = {price = 50, storage = Storage.TheNewFrontier.Mission03, value = 1}
}
function StdModule.travelDiscount(player, discounts)
 local discountPrice, discount = 0
 if type(discounts) == 'string' then
  discount = travelDiscounts[discounts]
  if discount and player:getStorageValue(discount.storage) >= discount.value then
   return discount.price
  end
 else
  for i = 1, #discounts do
   discount = travelDiscounts[discounts[i]]
   if discount and player:getStorageValue(discount.storage) >= discount.value then
    discountPrice = discountPrice + discount.price
   end
  end
 end
 return discountPrice
end
function StdModule.kick(cid, message, keywords, parameters, node)
 local npcHandler = parameters.npcHandler
 if npcHandler == nil then
  error("StdModule.travel called without any npcHandler instance.")
 end
 if not npcHandler:isFocused(cid) then
  return false
 end
 npcHandler:releaseFocus(cid)
 npcHandler:say(parameters.text or "Off with you!", cid)
 local destination = parameters.destination
 if type(destination) == 'table' then
  destination = destination[math.random(#destination)]
 end
 Player(cid):teleportTo(destination, true)
 npcHandler:resetNpc(cid)
 return true
end
local GreetModule = {}
function GreetModule.greet(cid, message, keywords, parameters)
 if not parameters.npcHandler:isInRange(cid) then
  return true
 end
 if parameters.npcHandler:isFocused(cid) then
  return true
 end
 local parseInfo = { [TAG_PLAYERNAME] = Player(cid):getName() }
 parameters.npcHandler:say(parameters.npcHandler:parseMessage(parameters.text, parseInfo), cid, true)
 parameters.npcHandler:addFocus(cid)
 return true
end
function GreetModule.farewell(cid, message, keywords, parameters)
 if not parameters.npcHandler:isFocused(cid) then
  return false
 end
 local parseInfo = { [TAG_PLAYERNAME] = Player(cid):getName() }
 parameters.npcHandler:say(parameters.npcHandler:parseMessage(parameters.text, parseInfo), cid, true)
 parameters.npcHandler:resetNpc(cid)
 parameters.npcHandler:releaseFocus(cid)
 return true
end
-- Adds a keyword which acts as a greeting word
function KeywordHandler:addGreetKeyword(keys, parameters, condition, action)
 local keys = keys
 keys.callback = FocusModule.messageMatcherDefault
 return self:addKeyword(keys, GreetModule.greet, parameters, condition, action)
end
-- Adds a keyword which acts as a farewell word
function KeywordHandler:addFarewellKeyword(keys, parameters, condition, action)
 local keys = keys
 keys.callback = FocusModule.messageMatcherDefault
 return self:addKeyword(keys, GreetModule.farewell, parameters, condition, action)
end
-- Adds a keyword which acts as a spell word
function KeywordHandler:addSpellKeyword(keys, parameters)
 local keys = keys
 keys.callback = FocusModule.messageMatcherDefault
 local npcHandler, spellName, price, vocationId = parameters.npcHandler, parameters.spellName, parameters.price, parameters.vocation
 local spellKeyword = self:addKeyword(keys, StdModule.say, {npcHandler = npcHandler, text = string.format("Do you want to learn the spell '%s' for %s?", spellName, price > 0 and price .. ' gold' or 'free')},
  function(player)
   local baseVocationId = player:getVocation():getBase():getId()
   if type(vocationId) == 'table' then
    return isInArray(vocationId, baseVocationId)
   else
    return vocationId == baseVocationId
   end
  end
 )
 spellKeyword:addChildKeyword({'yes'}, StdModule.learnSpell, {npcHandler = npcHandler, spellName = spellName, level = parameters.level, price = price})
 spellKeyword:addChildKeyword({'no'}, StdModule.say, {npcHandler = npcHandler, text = 'Maybe next time.', reset = true})
end
local hints = {
 [-1] = 'If you don\'t know the meaning of an icon on the right side, move the mouse cursor on it and wait a moment.',
 [0] = 'Send private messages to other players by right-clicking on the player or the player\'s name and select \'Message to ....\'. You can also open a \'private message channel\' and type in the name of the player.',
 [1] = 'Use the shortcuts \'SHIFT\' to look, \'CTRL\' for use and \'ALT\' for attack when clicking on an object or player.',
 [2] = 'If you already know where you want to go, click on the automap and your character will walk there automatically if the location is reachable and not too far away.',
 [3] = 'To open or close skills, battle or VIP list, click on the corresponding button to the right.',
 [4] = '\'Capacity\' restricts the amount of things you can carry with you. It raises with each level.',
 [5] = 'Always have a look on your health bar. If you see that you do not regenerate health points anymore, eat something.',
 [6] = 'Always eat as much food as possible. This way, you\'ll regenerate health points for a longer period of time.',
 [7] = 'After you have killed a monster, you have 10 seconds in which the corpse is not moveable and no one else but you can loot it.',
 [8] = 'Be careful when you approach three or more monsters because you only can block the attacks of two. In such a situation even a few rats can do severe damage or even kill you.',
 [9] = 'There are many ways to gather food. Many creatures drop food but you can also pick blueberries or bake your own bread. If you have a fishing rod and worms in your inventory, you can also try to catch a fish.',
 [10] = {'Baking bread is rather complex. First of all you need a scythe to harvest wheat. Then you use the wheat with a millstone to get flour. ...', 'This can be be used on water to get dough, which can be used on an oven to bake bread. Use milk instead of water to get cake dough.'},
 [11] = 'Dying hurts! Better run away than risk your life. You are going to lose experience and skill points when you die.',
 [12] = 'When you switch to \'Offensive Fighting\', you deal out more damage but you also get hurt more easily.',
 [13] = 'When you are on low health and need to run away from a monster, switch to \'Defensive Fighting\' and the monster will hit you less severely.',
 [14] = 'Many creatures try to run away from you. Select \'Chase Opponent\' to follow them.',
 [15] = 'The deeper you enter a dungeon, the more dangerous it will be. Approach every dungeon with utmost care or an unexpected creature might kill you. This will result in losing experience and skill points.',
 [16] = 'Due to the perspective, some objects in Tibia are not located at the spot they seem to appear (ladders, windows, lamps). Try clicking on the floor tile the object would lie on.',
 [17] = 'If you want to trade an item with another player, right-click on the item and select \'Trade with ...\', then click on the player with whom you want to trade.',
 [18] = 'Stairs, ladders and dungeon entrances are marked as yellow dots on the automap.',
 [19] = 'You can get food by killing animals or monsters. You can also pick blueberries or bake your own bread. If you are too lazy or own too much money, you can also buy food.',
 [20] = 'Quest containers can be recognised easily. They don\'t open up regularly but display a message \'You have found ....\'. They can only be opened once.',
 [21] = 'Better run away than risk to die. You\'ll lose experience and skill points each time you die.',
 [22] = 'You can form a party by right-clicking on a player and selecting \'Invite to Party\'. The party leader can also enable \'Shared Experience\' by right-clicking on him- or herself.',
 [23] = 'You can assign spells, the use of items, or random text to \'hotkeys\'. You find them under \'Options\'.',
 [24] = 'You can also follow other players. Just right-click on the player and select \'Follow\'.',
 [25] = 'You can found a party with your friends by right-clicking on a player and selecting \'Invite to Party\'. If you are invited to a party, right-click on yourself and select \'Join Party\'.',
 [26] = 'Only found parties with people you trust. You can attack people in your party without getting a skull. This is helpful for training your skills, but can be abused to kill people without having to fear negative consequences.',
 [27] = 'The leader of a party has the option to distribute gathered experience among all players in the party. If you are the leader, right-click on yourself and select \'Enable Shared Experience\'.',
 [28] = 'There is nothing more I can tell you. If you are still in need of some {hints}, I can repeat them for you.'
}
function StdModule.rookgaardHints(cid, message, keywords, parameters, node)
 local npcHandler = parameters.npcHandler
 if npcHandler == nil then
  error("StdModule.say called without any npcHandler instance.")
 end
 if not npcHandler:isFocused(cid) then
  return false
 end
 local player = Player(cid)
 local hintId = player:getStorageValue(Storage.RookgaardHints)
 npcHandler:say(hints[hintId], cid)
 if hintId >= #hints then
  player:setStorageValue(Storage.RookgaardHints, -1)
 else
  player:setStorageValue(Storage.RookgaardHints, hintId + 1)
 end
 return true
end
-- VoiceModule
VoiceModule = {
   voices = nil,
   voiceCount = 0,
   lastVoice = 0,
   timeout = nil,
   chance = nil,
   npcHandler = nil
}
 
-- Creates a new instance of VoiceModule
function VoiceModule:new(voices, timeout, chance)
   local obj = {}
   setmetatable(obj, self)
   self.__index = self
 
   obj.voices = voices
   for i = 1, #obj.voices do
       if obj.voices[i].yell then
           obj.voices[i].yell = nil
           obj.voices[i].talktype = TALKTYPE_YELL
       else
           obj.voices[i].talktype = TALKTYPE_SAY
       end
   end
 
   obj.voiceCount = #voices
   obj.timeout = timeout or 10
   obj.chance = chance or 25
   return obj
end
 
function VoiceModule:init(handler)
   return true
end
 
function VoiceModule:callbackOnThink()
   if self.lastVoice < os.time() then
       self.lastVoice = os.time() + self.timeout
       if math.random(100) < self.chance  then
           local voice = self.voices[math.random(self.voiceCount)]
           Npc():say(voice.text, voice.talktype)
       end
   end
   return true
end
 
It looks like its incomplete (the top 4 lines)

Try adding this at the top of your file

local travelDiscounts = {
 
It looks like its incomplete (the top 4 lines)

Try adding this at the top of your file

local travelDiscounts = {

It's there I just forgot to copy and paste that portion.

Lua:
local travelDiscounts = {
 ['postman'] = {price = 10, storage = Storage.postman.Rank, value = 3},
 ['new frontier'] = {price = 50, storage = Storage.TheNewFrontier.Mission03, value = 1}
}
 
It sounds like this datapack didn't come with the distribution by messing with the lib for npc's he might mess up his other npc's.
@Scuss21 that error "attempt to index global 'Storage' (a nil value)" to resolve it you could just add to global.lua
Code:
Storage = {}
But then you would need to add in all the missing properties and their default values... what distribution did you get this datapack from?
 
It sounds like this datapack didn't come with the distribution by messing with the lib for npc's he might mess up his other npc's.
@Scuss21 that error "attempt to index global 'Storage' (a nil value)" to resolve it you could just add to global.lua
Code:
Storage = {}
But then you would need to add in all the missing properties and their default values... what distribution did you get this datapack from?

Pulled it from a 10.98 RealServer from the distributions forum, most of the NPCs are there, just mostly the boat NPC aren't working and I'm trying to figure it out myself but I've been rattling my brain about it so I've came here for a little help.
 
It sounds like this datapack didn't come with the distribution by messing with the lib for npc's he might mess up his other npc's.
@Scuss21 that error "attempt to index global 'Storage' (a nil value)" to resolve it you could just add to global.lua
Code:
Storage = {}
But then you would need to add in all the missing properties and their default values... what distribution did you get this datapack from?

Added that into my global.lua file seemed to have changed the error message to:
data/npc/lib/npcsystem/customModules.lua:3: attempt to index field 'postman' (a nil value)

Lua:
local travelDiscounts = {
 ['postman'] = {price = 10, storage = Storage.postman.Rank, value = 3},
 ['new frontier'] = {price = 50, storage = Storage.TheNewFrontier.Mission03, value = 1}
}
function StdModule.travelDiscount(player, discounts)
 local discountPrice, discount = 0
 if type(discounts) == 'string' then
  discount = travelDiscounts[discounts]
  if discount and player:getStorageValue(discount.storage) >= discount.value then
   return discount.price
  end
 else
  for i = 1, #discounts do
   discount = travelDiscounts[discounts[i]]
   if discount and player:getStorageValue(discount.storage) >= discount.value then
    discountPrice = discountPrice + discount.price
   end
  end
 end
 return discountPrice
end
function StdModule.kick(cid, message, keywords, parameters, node)
 local npcHandler = parameters.npcHandler
 if npcHandler == nil then
  error("StdModule.travel called without any npcHandler instance.")
 end
 if not npcHandler:isFocused(cid) then
  return false
 end
 npcHandler:releaseFocus(cid)
 npcHandler:say(parameters.text or "Off with you!", cid)
 local destination = parameters.destination
 if type(destination) == 'table' then
  destination = destination[math.random(#destination)]
 end
 Player(cid):teleportTo(destination, true)
 npcHandler:resetNpc(cid)
 return true
end
local GreetModule = {}
function GreetModule.greet(cid, message, keywords, parameters)
 if not parameters.npcHandler:isInRange(cid) then
  return true
 end
 if parameters.npcHandler:isFocused(cid) then
  return true
 end
 local parseInfo = { [TAG_PLAYERNAME] = Player(cid):getName() }
 parameters.npcHandler:say(parameters.npcHandler:parseMessage(parameters.text, parseInfo), cid, true)
 parameters.npcHandler:addFocus(cid)
 return true
end
function GreetModule.farewell(cid, message, keywords, parameters)
 if not parameters.npcHandler:isFocused(cid) then
  return false
 end
 local parseInfo = { [TAG_PLAYERNAME] = Player(cid):getName() }
 parameters.npcHandler:say(parameters.npcHandler:parseMessage(parameters.text, parseInfo), cid, true)
 parameters.npcHandler:resetNpc(cid)
 parameters.npcHandler:releaseFocus(cid)
 return true
end
-- Adds a keyword which acts as a greeting word
function KeywordHandler:addGreetKeyword(keys, parameters, condition, action)
 local keys = keys
 keys.callback = FocusModule.messageMatcherDefault
 return self:addKeyword(keys, GreetModule.greet, parameters, condition, action)
end
-- Adds a keyword which acts as a farewell word
function KeywordHandler:addFarewellKeyword(keys, parameters, condition, action)
 local keys = keys
 keys.callback = FocusModule.messageMatcherDefault
 return self:addKeyword(keys, GreetModule.farewell, parameters, condition, action)
end
-- Adds a keyword which acts as a spell word
function KeywordHandler:addSpellKeyword(keys, parameters)
 local keys = keys
 keys.callback = FocusModule.messageMatcherDefault
 local npcHandler, spellName, price, vocationId = parameters.npcHandler, parameters.spellName, parameters.price, parameters.vocation
 local spellKeyword = self:addKeyword(keys, StdModule.say, {npcHandler = npcHandler, text = string.format("Do you want to learn the spell '%s' for %s?", spellName, price > 0 and price .. ' gold' or 'free')},
  function(player)
   local baseVocationId = player:getVocation():getBase():getId()
   if type(vocationId) == 'table' then
    return isInArray(vocationId, baseVocationId)
   else
    return vocationId == baseVocationId
   end
  end
 )
 spellKeyword:addChildKeyword({'yes'}, StdModule.learnSpell, {npcHandler = npcHandler, spellName = spellName, level = parameters.level, price = price})
 spellKeyword:addChildKeyword({'no'}, StdModule.say, {npcHandler = npcHandler, text = 'Maybe next time.', reset = true})
end
local hints = {
 [-1] = 'If you don\'t know the meaning of an icon on the right side, move the mouse cursor on it and wait a moment.',
 [0] = 'Send private messages to other players by right-clicking on the player or the player\'s name and select \'Message to ....\'. You can also open a \'private message channel\' and type in the name of the player.',
 [1] = 'Use the shortcuts \'SHIFT\' to look, \'CTRL\' for use and \'ALT\' for attack when clicking on an object or player.',
 [2] = 'If you already know where you want to go, click on the automap and your character will walk there automatically if the location is reachable and not too far away.',
 [3] = 'To open or close skills, battle or VIP list, click on the corresponding button to the right.',
 [4] = '\'Capacity\' restricts the amount of things you can carry with you. It raises with each level.',
 [5] = 'Always have a look on your health bar. If you see that you do not regenerate health points anymore, eat something.',
 [6] = 'Always eat as much food as possible. This way, you\'ll regenerate health points for a longer period of time.',
 [7] = 'After you have killed a monster, you have 10 seconds in which the corpse is not moveable and no one else but you can loot it.',
 [8] = 'Be careful when you approach three or more monsters because you only can block the attacks of two. In such a situation even a few rats can do severe damage or even kill you.',
 [9] = 'There are many ways to gather food. Many creatures drop food but you can also pick blueberries or bake your own bread. If you have a fishing rod and worms in your inventory, you can also try to catch a fish.',
 [10] = {'Baking bread is rather complex. First of all you need a scythe to harvest wheat. Then you use the wheat with a millstone to get flour. ...', 'This can be be used on water to get dough, which can be used on an oven to bake bread. Use milk instead of water to get cake dough.'},
 [11] = 'Dying hurts! Better run away than risk your life. You are going to lose experience and skill points when you die.',
 [12] = 'When you switch to \'Offensive Fighting\', you deal out more damage but you also get hurt more easily.',
 [13] = 'When you are on low health and need to run away from a monster, switch to \'Defensive Fighting\' and the monster will hit you less severely.',
 [14] = 'Many creatures try to run away from you. Select \'Chase Opponent\' to follow them.',
 [15] = 'The deeper you enter a dungeon, the more dangerous it will be. Approach every dungeon with utmost care or an unexpected creature might kill you. This will result in losing experience and skill points.',
 [16] = 'Due to the perspective, some objects in Tibia are not located at the spot they seem to appear (ladders, windows, lamps). Try clicking on the floor tile the object would lie on.',
 [17] = 'If you want to trade an item with another player, right-click on the item and select \'Trade with ...\', then click on the player with whom you want to trade.',
 [18] = 'Stairs, ladders and dungeon entrances are marked as yellow dots on the automap.',
 [19] = 'You can get food by killing animals or monsters. You can also pick blueberries or bake your own bread. If you are too lazy or own too much money, you can also buy food.',
 [20] = 'Quest containers can be recognised easily. They don\'t open up regularly but display a message \'You have found ....\'. They can only be opened once.',
 [21] = 'Better run away than risk to die. You\'ll lose experience and skill points each time you die.',
 [22] = 'You can form a party by right-clicking on a player and selecting \'Invite to Party\'. The party leader can also enable \'Shared Experience\' by right-clicking on him- or herself.',
 [23] = 'You can assign spells, the use of items, or random text to \'hotkeys\'. You find them under \'Options\'.',
 [24] = 'You can also follow other players. Just right-click on the player and select \'Follow\'.',
 [25] = 'You can found a party with your friends by right-clicking on a player and selecting \'Invite to Party\'. If you are invited to a party, right-click on yourself and select \'Join Party\'.',
 [26] = 'Only found parties with people you trust. You can attack people in your party without getting a skull. This is helpful for training your skills, but can be abused to kill people without having to fear negative consequences.',
 [27] = 'The leader of a party has the option to distribute gathered experience among all players in the party. If you are the leader, right-click on yourself and select \'Enable Shared Experience\'.',
 [28] = 'There is nothing more I can tell you. If you are still in need of some {hints}, I can repeat them for you.'
}
function StdModule.rookgaardHints(cid, message, keywords, parameters, node)
 local npcHandler = parameters.npcHandler
 if npcHandler == nil then
  error("StdModule.say called without any npcHandler instance.")
 end
 if not npcHandler:isFocused(cid) then
  return false
 end
 local player = Player(cid)
 local hintId = player:getStorageValue(Storage.RookgaardHints)
 npcHandler:say(hints[hintId], cid)
 if hintId >= #hints then
  player:setStorageValue(Storage.RookgaardHints, -1)
 else
  player:setStorageValue(Storage.RookgaardHints, hintId + 1)
 end
 return true
end
-- VoiceModule
VoiceModule = {
   voices = nil,
   voiceCount = 0,
   lastVoice = 0,
   timeout = nil,
   chance = nil,
   npcHandler = nil
}
 
-- Creates a new instance of VoiceModule
function VoiceModule:new(voices, timeout, chance)
   local obj = {}
   setmetatable(obj, self)
   self.__index = self
 
   obj.voices = voices
   for i = 1, #obj.voices do
       if obj.voices[i].yell then
           obj.voices[i].yell = nil
           obj.voices[i].talktype = TALKTYPE_YELL
       else
           obj.voices[i].talktype = TALKTYPE_SAY
       end
   end
 
   obj.voiceCount = #voices
   obj.timeout = timeout or 10
   obj.chance = chance or 25
   return obj
end
 
function VoiceModule:init(handler)
   return true
end
 
function VoiceModule:callbackOnThink()
   if self.lastVoice < os.time() then
       self.lastVoice = os.time() + self.timeout
       if math.random(100) < self.chance  then
           local voice = self.voices[math.random(self.voiceCount)]
           Npc():say(voice.text, voice.talktype)
       end
   end
   return true
end
 
Added that into my global.lua file seemed to have changed the error message to:
data/npc/lib/npcsystem/customModules.lua:3: attempt to index field 'postman' (a nil value)
That's what I meant by you need to add in all the missing properties of Storage
['postman'] = {price = 10, storage = Storage.postman.Rank, value = 3},
['new frontier'] = {price = 50, storage = Storage.TheNewFrontier.Mission03, value = 1}

I color coded it for you, Storage is the table we just added and it is colored in Red, the sub table which is colored Orange is not defined in Storage, this table is a property of Storage, and the last color is colored in Blue is also a property of Storage, but a property of Storage's sub-table that is colored in orange.. yes its confusing i know..

Under these circumstances i would do a search through that datapack for things like Rank, Mission03, postman, TheNewFrontier and try to find the base table with all these values, then add that table to global.lua otherwise we are just going to be chasing our tails trying to correct every error in regards to these files that come from that datapack.
 
Back
Top