• 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!
  • 2026 staff recruitment is open! Check it out and consider applying!

NPC - Say something

CyberShaman21

New Member
Joined
Dec 9, 2017
Messages
52
Reaction score
4
Hi
I use tfs 1.2
I wonder, how to make fix for npc.
I want to make npc say something at times.
Code:
<?xml version="1.0" encoding="UTF-8"?>
<npc name="xxx" script="xxx.lua" walkinterval="2000" floorchange="0">
    <health now="100" max="100" />
    <look type="132" head="20" body="39" legs="45" feet="7" addons="0" />
    <parameters>
        <parameter key="module_shop" value="1" />
        <parameter key="shop_buyable" value="parcel,2595,15;letter,2597,10" />
    </parameters>
</npc>
i add voices from monster
Code:
<?xml version="1.0" encoding="UTF-8"?>
<npc name="xxx" script="xxx.lua" walkinterval="2000" floorchange="0">
    <health now="100" max="100" />
    <look type="132" head="20" body="39" legs="45" feet="7" addons="0" />
    <parameters>
        <parameter key="module_shop" value="1" />
        <parameter key="shop_buyable" value="parcel,2595,15;letter,2597,10" />
    </parameters>
    <voices interval="10" chance="100000">
        <voice sentence="Ranat Ulderek!" />
        <voice sentence="Orc buta bana!" />
        <voice sentence="Ikem rambo zambo!" />
        <voice sentence="Futchi maruk buta!" />
    </voices>
</npc>
but dosen't work

i found in orts server this:
server/data/npc/scripts/Obi.lua
Code:
local voices = {
    { text = 'Only quality steel and wood used for my weapons!' },
    { text = 'Buy your weapons here!' },
    { text = 'Selling and buying all sorts of weapons, come and have a look!' },
    { text = 'Give those monsters a good whipping with my weapons!' }
}
npcHandler:addModule(VoiceModule:new(voices))


i try to copy this and add to TFS 1.2 but i get error.
Code:
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

npcHandler:addModule(FocusModule:new())

local voices = {
    { text = 'Only quality steel and wood used for my weapons!' },
    { text = 'Buy your weapons here!' },
    { text = 'Selling and buying all sorts of weapons, come and have a look!' },
    { text = 'Give those monsters a good whipping with my weapons!' }
}
npcHandler:addModule(VoiceModule:new(voices))
I copy folder lib from npc folder(orts) ind paste to tfs 1.2 and still errors
What i need to fix?
 
Solution
Thanks, but when i copy all folder lib form orts to tfs I should have this functions.
I try copy this
Code:
-- 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
        local voice = obj.voices[i]
        if voice.yell then
            voice.yell = nil
            voice.talktype = TALKTYPE_YELL
        else
            voice.talktype = TALKTYPE_SAY
        end
    end

    obj.voiceCount = #voices
    obj.timeout = timeout or 10...
Hi
I use tfs 1.2
I wonder, how to make fix for npc.
I want to make npc say something at times.
Code:
<?xml version="1.0" encoding="UTF-8"?>
<npc name="xxx" script="xxx.lua" walkinterval="2000" floorchange="0">
    <health now="100" max="100" />
    <look type="132" head="20" body="39" legs="45" feet="7" addons="0" />
    <parameters>
        <parameter key="module_shop" value="1" />
        <parameter key="shop_buyable" value="parcel,2595,15;letter,2597,10" />
    </parameters>
</npc>
i add voices from monster
Code:
<?xml version="1.0" encoding="UTF-8"?>
<npc name="xxx" script="xxx.lua" walkinterval="2000" floorchange="0">
    <health now="100" max="100" />
    <look type="132" head="20" body="39" legs="45" feet="7" addons="0" />
    <parameters>
        <parameter key="module_shop" value="1" />
        <parameter key="shop_buyable" value="parcel,2595,15;letter,2597,10" />
    </parameters>
    <voices interval="10" chance="100000">
        <voice sentence="Ranat Ulderek!" />
        <voice sentence="Orc buta bana!" />
        <voice sentence="Ikem rambo zambo!" />
        <voice sentence="Futchi maruk buta!" />
    </voices>
</npc>
but dosen't work

i found in orts server this:
server/data/npc/scripts/Obi.lua
Code:
local voices = {
    { text = 'Only quality steel and wood used for my weapons!' },
    { text = 'Buy your weapons here!' },
    { text = 'Selling and buying all sorts of weapons, come and have a look!' },
    { text = 'Give those monsters a good whipping with my weapons!' }
}
npcHandler:addModule(VoiceModule:new(voices))


i try to copy this and add to TFS 1.2 but i get error.
Code:
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

npcHandler:addModule(FocusModule:new())

local voices = {
    { text = 'Only quality steel and wood used for my weapons!' },
    { text = 'Buy your weapons here!' },
    { text = 'Selling and buying all sorts of weapons, come and have a look!' },
    { text = 'Give those monsters a good whipping with my weapons!' }
}
npcHandler:addModule(VoiceModule:new(voices))
I copy folder lib from npc folder(orts) ind paste to tfs 1.2 and still errors
What i need to fix?

The error is because you are missing those functions; server/customModules.lua at master · orts/server · GitHub
 
Thanks, but when i copy all folder lib form orts to tfs I should have this functions.
I try copy this
Code:
-- 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
        local voice = obj.voices[i]
        if voice.yell then
            voice.yell = nil
            voice.talktype = TALKTYPE_YELL
        else
            voice.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

and paste to modules.lua
Code:
-- Advanced NPC System by Jiddo

if Modules == nil then
    -- default words for greeting and ungreeting the npc. Should be a table containing all such words.
    FOCUS_GREETWORDS = {"hi", "hello"}
    FOCUS_FAREWELLWORDS = {"bye", "farewell"}

    -- The words for requesting trade window.
    SHOP_TRADEREQUEST = {"trade"}

   (...)

    -- onModuleReset callback function. Calls ShopModule:reset()
    function ShopModule:callbackOnModuleReset()
        self:reset()
        return true
    end

    -- Callback onBuy() function. If you wish, you can change certain Npc to use your onBuy().
    function ShopModule:callbackOnBuy(cid, itemid, subType, amount, ignoreCap, inBackpacks)
        local shopItem = self:getShopItem(itemid, subType)
        if shopItem == nil then
            error("[ShopModule.onBuy] shopItem == nil")
            return false
        end

        if shopItem.buy == -1 then
            error("[ShopModule.onSell] attempt to buy a non-buyable item")
            return false
        end

        local backpack = 1988
        local totalCost = amount * shopItem.buy
        if inBackpacks then
            totalCost = isItemStackable(itemid) == TRUE and totalCost + 20 or totalCost + (math.max(1, math.floor(amount / getContainerCapById(backpack))) * 20)
        end

        local parseInfo = {
            [TAG_PLAYERNAME] = getPlayerName(cid),
            [TAG_ITEMCOUNT] = amount,
            [TAG_TOTALCOST] = totalCost,
            [TAG_ITEMNAME] = shopItem.name
        }

        if getPlayerMoney(cid) < totalCost then
            local msg = self.npcHandler:getMessage(MESSAGE_NEEDMONEY)
            msg = self.npcHandler:parseMessage(msg, parseInfo)
            doPlayerSendCancel(cid, msg)
            return false
        end

        local subType = shopItem.subType or 1
        local a, b = doNpcSellItem(cid, itemid, amount, subType, ignoreCap, inBackpacks, backpack)
        if a < amount then
            local msgId = MESSAGE_NEEDMORESPACE
            if a == 0 then
                msgId = MESSAGE_NEEDSPACE
            end

            local msg = self.npcHandler:getMessage(msgId)
            parseInfo[TAG_ITEMCOUNT] = a
            msg = self.npcHandler:parseMessage(msg, parseInfo)
            doPlayerSendCancel(cid, msg)
            self.npcHandler.talkStart[cid] = os.time()

            if a > 0 then
                doPlayerRemoveMoney(cid, ((a * shopItem.buy) + (b * 20)))
                return true
            end

            return false
        else
            local msg = self.npcHandler:getMessage(MESSAGE_BOUGHT)
            msg = self.npcHandler:parseMessage(msg, parseInfo)
            doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, msg)
            doPlayerRemoveMoney(cid, totalCost)
            self.npcHandler.talkStart[cid] = os.time()
            return true
        end
    end

    -- Callback onSell() function. If you wish, you can change certain Npc to use your onSell().
    function ShopModule:callbackOnSell(cid, itemid, subType, amount, ignoreEquipped, _)
        local shopItem = self:getShopItem(itemid, subType)
        if shopItem == nil then
            error("[ShopModule.onSell] items[itemid] == nil")
            return false
        end

        if shopItem.sell == -1 then
            error("[ShopModule.onSell] attempt to sell a non-sellable item")
            return false
        end

        local parseInfo = {
            [TAG_PLAYERNAME] = getPlayerName(cid),
            [TAG_ITEMCOUNT] = amount,
            [TAG_TOTALCOST] = amount * shopItem.sell,
            [TAG_ITEMNAME] = shopItem.name
        }

        if not isItemFluidContainer(itemid) then
            subType = -1
        end

        if doPlayerRemoveItem(cid, itemid, amount, subType, ignoreEquipped) then
            local msg = self.npcHandler:getMessage(MESSAGE_SOLD)
            msg = self.npcHandler:parseMessage(msg, parseInfo)
            doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, msg)
            doPlayerAddMoney(cid, amount * shopItem.sell)
            self.npcHandler.talkStart[cid] = os.time()
            return true
        else
            local msg = self.npcHandler:getMessage(MESSAGE_NEEDITEM)
            msg = self.npcHandler:parseMessage(msg, parseInfo)
            doPlayerSendCancel(cid, msg)
            self.npcHandler.talkStart[cid] = os.time()
            return false
        end
    end

    -- Callback for requesting a trade window with the NPC.
    function ShopModule.requestTrade(cid, message, keywords, parameters, node)
        local module = parameters.module
        if not module.npcHandler:isFocused(cid) then
            return false
        end

        if not module.npcHandler:onTradeRequest(cid) then
            return false
        end

        local itemWindow = {}
        for i = 1, #module.npcHandler.shopItems do
            itemWindow[#itemWindow + 1] = module.npcHandler.shopItems[i]
        end

        if itemWindow[1] == nil then
            local parseInfo = { [TAG_PLAYERNAME] = getPlayerName(cid) }
            local msg = module.npcHandler:parseMessage(module.npcHandler:getMessage(MESSAGE_NOSHOP), parseInfo)
            module.npcHandler:say(msg, cid)
            return true
        end

        local parseInfo = { [TAG_PLAYERNAME] = getPlayerName(cid) }
        local msg = module.npcHandler:parseMessage(module.npcHandler:getMessage(MESSAGE_SENDTRADE), parseInfo)
        openShopWindow(cid, itemWindow,
            function(cid, itemid, subType, amount, ignoreCap, inBackpacks) module.npcHandler:onBuy(cid, itemid, subType, amount, ignoreCap, inBackpacks) end,
            function(cid, itemid, subType, amount, ignoreCap, inBackpacks) module.npcHandler:onSell(cid, itemid, subType, amount, ignoreCap, inBackpacks) end)
        module.npcHandler:say(msg, cid)
        return true
    end

    -- onConfirm keyword callback function. Sells/buys the actual item.
    function ShopModule.onConfirm(cid, message, keywords, parameters, node)
        local module = parameters.module
        if not module.npcHandler:isFocused(cid) or shop_npcuid[cid] ~= getNpcCid() then
            return false
        end
        shop_npcuid[cid] = 0

        local parentParameters = node:getParent():getParameters()
        local parseInfo = {
            [TAG_PLAYERNAME] = getPlayerName(cid),
            [TAG_ITEMCOUNT] = shop_amount[cid],
            [TAG_TOTALCOST] = shop_cost[cid] * shop_amount[cid],
            [TAG_ITEMNAME] = shop_rlname[cid]
        }

        if shop_eventtype[cid] == SHOPMODULE_SELL_ITEM then
            local ret = doPlayerSellItem(cid, shop_itemid[cid], shop_amount[cid], shop_cost[cid] * shop_amount[cid])
            if ret == true then
                local msg = module.npcHandler:getMessage(MESSAGE_ONSELL)
                msg = module.npcHandler:parseMessage(msg, parseInfo)
                module.npcHandler:say(msg, cid)
            else
                local msg = module.npcHandler:getMessage(MESSAGE_MISSINGITEM)
                msg = module.npcHandler:parseMessage(msg, parseInfo)
                module.npcHandler:say(msg, cid)
            end
        elseif shop_eventtype[cid] == SHOPMODULE_BUY_ITEM then
            local cost = shop_cost[cid] * shop_amount[cid]
            if getPlayerMoney(cid) < cost then
                local msg = module.npcHandler:getMessage(MESSAGE_MISSINGMONEY)
                msg = module.npcHandler:parseMessage(msg, parseInfo)
                module.npcHandler:say(msg, cid)
                return false
            end

            local a, b = doNpcSellItem(cid, shop_itemid[cid], shop_amount[cid], shop_subtype[cid], false, false, 1988)
            if a < shop_amount[cid] then
                local msgId = MESSAGE_NEEDMORESPACE
                if a == 0 then
                    msgId = MESSAGE_NEEDSPACE
                end

                local msg = module.npcHandler:getMessage(msgId)
                msg = module.npcHandler:parseMessage(msg, parseInfo)
                module.npcHandler:say(msg, cid)
                if a > 0 then
                    doPlayerRemoveMoney(cid, a * shop_cost[cid])
                    if shop_itemid[cid] == ITEM_PARCEL then
                        doNpcSellItem(cid, ITEM_LABEL, shop_amount[cid], shop_subtype[cid], true, false, 1988)
                    end
                    return true
                end
                return false
            else
                local msg = module.npcHandler:getMessage(MESSAGE_ONBUY)
                msg = module.npcHandler:parseMessage(msg, parseInfo)
                module.npcHandler:say(msg, cid)
                doPlayerRemoveMoney(cid, cost)
                if shop_itemid[cid] == ITEM_PARCEL then
                    doNpcSellItem(cid, ITEM_LABEL, shop_amount[cid], shop_subtype[cid], true, false, 1988)
                end
                return true
            end
        elseif shop_eventtype[cid] == SHOPMODULE_BUY_ITEM_CONTAINER then
            local ret = doPlayerBuyItemContainer(cid, shop_container[cid], shop_itemid[cid], shop_amount[cid], shop_cost[cid] * shop_amount[cid], shop_subtype[cid])
            if ret == true then
                local msg = module.npcHandler:getMessage(MESSAGE_ONBUY)
                msg = module.npcHandler:parseMessage(msg, parseInfo)
                module.npcHandler:say(msg, cid)
            else
                local msg = module.npcHandler:getMessage(MESSAGE_MISSINGMONEY)
                msg = module.npcHandler:parseMessage(msg, parseInfo)
                module.npcHandler:say(msg, cid)
            end
        end

        module.npcHandler:resetNpc(cid)
        return true
    end

    -- onDecline keyword callback function. Generally called when the player sais "no" after wanting to buy an item.
    function ShopModule.onDecline(cid, message, keywords, parameters, node)
        local module = parameters.module
        if not module.npcHandler:isFocused(cid) or shop_npcuid[cid] ~= getNpcCid() then
            return false
        end
        shop_npcuid[cid] = 0

        local parentParameters = node:getParent():getParameters()
        local parseInfo = {
            [TAG_PLAYERNAME] = getPlayerName(cid),
            [TAG_ITEMCOUNT] = shop_amount[cid],
            [TAG_TOTALCOST] = shop_cost[cid] * shop_amount[cid],
            [TAG_ITEMNAME] = shop_rlname[cid]
        }

        local msg = module.npcHandler:parseMessage(module.noText, parseInfo)
        module.npcHandler:say(msg, cid)
        module.npcHandler:resetNpc(cid)
        return true
    end

    -- tradeItem callback function. Makes the npc say the message defined by MESSAGE_BUY or MESSAGE_SELL
    function ShopModule.tradeItem(cid, message, keywords, parameters, node)
        local module = parameters.module
        if not module.npcHandler:isFocused(cid) then
            return false
        end

        if not module.npcHandler:onTradeRequest(cid) then
            return true
        end

        local count = module:getCount(message)
        module.amount = count

        shop_amount[cid] = module.amount
        shop_cost[cid] = parameters.cost
        shop_rlname[cid] = parameters.realName
        shop_itemid[cid] = parameters.itemid
        shop_container[cid] = parameters.container
        shop_npcuid[cid] = getNpcCid()
        shop_eventtype[cid] = parameters.eventType
        shop_subtype[cid] = parameters.subType

        local parseInfo = {
            [TAG_PLAYERNAME] = getPlayerName(cid),
            [TAG_ITEMCOUNT] = shop_amount[cid],
            [TAG_TOTALCOST] = shop_cost[cid] * shop_amount[cid],
            [TAG_ITEMNAME] = shop_rlname[cid]
        }

        if shop_eventtype[cid] == SHOPMODULE_SELL_ITEM then
            local msg = module.npcHandler:getMessage(MESSAGE_SELL)
            msg = module.npcHandler:parseMessage(msg, parseInfo)
            module.npcHandler:say(msg, cid)
        elseif shop_eventtype[cid] == SHOPMODULE_BUY_ITEM then
            local msg = module.npcHandler:getMessage(MESSAGE_BUY)
            msg = module.npcHandler:parseMessage(msg, parseInfo)
            module.npcHandler:say(msg, cid)
        elseif shop_eventtype[cid] == SHOPMODULE_BUY_ITEM_CONTAINER then
            local msg = module.npcHandler:getMessage(MESSAGE_BUY)
            msg = module.npcHandler:parseMessage(msg, parseInfo)
            module.npcHandler:say(msg, cid)
        end
        return true
    end
  
    function VoiceModule:new(voices, timeout, chance)
    local obj = {}
    setmetatable(obj, self)
    self.__index = self

    obj.voices = voices
    for i = 1, #obj.voices do
        local voice = obj.voices[i]
        if voice.yell then
            voice.yell = nil
            voice.talktype = TALKTYPE_YELL
        else
            voice.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
  
end

errors
 
Thanks, but when i copy all folder lib form orts to tfs I should have this functions.
I try copy this
Code:
-- 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
        local voice = obj.voices[i]
        if voice.yell then
            voice.yell = nil
            voice.talktype = TALKTYPE_YELL
        else
            voice.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

and paste to modules.lua
Code:
-- Advanced NPC System by Jiddo

if Modules == nil then
    -- default words for greeting and ungreeting the npc. Should be a table containing all such words.
    FOCUS_GREETWORDS = {"hi", "hello"}
    FOCUS_FAREWELLWORDS = {"bye", "farewell"}

    -- The words for requesting trade window.
    SHOP_TRADEREQUEST = {"trade"}

   (...)

    -- onModuleReset callback function. Calls ShopModule:reset()
    function ShopModule:callbackOnModuleReset()
        self:reset()
        return true
    end

    -- Callback onBuy() function. If you wish, you can change certain Npc to use your onBuy().
    function ShopModule:callbackOnBuy(cid, itemid, subType, amount, ignoreCap, inBackpacks)
        local shopItem = self:getShopItem(itemid, subType)
        if shopItem == nil then
            error("[ShopModule.onBuy] shopItem == nil")
            return false
        end

        if shopItem.buy == -1 then
            error("[ShopModule.onSell] attempt to buy a non-buyable item")
            return false
        end

        local backpack = 1988
        local totalCost = amount * shopItem.buy
        if inBackpacks then
            totalCost = isItemStackable(itemid) == TRUE and totalCost + 20 or totalCost + (math.max(1, math.floor(amount / getContainerCapById(backpack))) * 20)
        end

        local parseInfo = {
            [TAG_PLAYERNAME] = getPlayerName(cid),
            [TAG_ITEMCOUNT] = amount,
            [TAG_TOTALCOST] = totalCost,
            [TAG_ITEMNAME] = shopItem.name
        }

        if getPlayerMoney(cid) < totalCost then
            local msg = self.npcHandler:getMessage(MESSAGE_NEEDMONEY)
            msg = self.npcHandler:parseMessage(msg, parseInfo)
            doPlayerSendCancel(cid, msg)
            return false
        end

        local subType = shopItem.subType or 1
        local a, b = doNpcSellItem(cid, itemid, amount, subType, ignoreCap, inBackpacks, backpack)
        if a < amount then
            local msgId = MESSAGE_NEEDMORESPACE
            if a == 0 then
                msgId = MESSAGE_NEEDSPACE
            end

            local msg = self.npcHandler:getMessage(msgId)
            parseInfo[TAG_ITEMCOUNT] = a
            msg = self.npcHandler:parseMessage(msg, parseInfo)
            doPlayerSendCancel(cid, msg)
            self.npcHandler.talkStart[cid] = os.time()

            if a > 0 then
                doPlayerRemoveMoney(cid, ((a * shopItem.buy) + (b * 20)))
                return true
            end

            return false
        else
            local msg = self.npcHandler:getMessage(MESSAGE_BOUGHT)
            msg = self.npcHandler:parseMessage(msg, parseInfo)
            doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, msg)
            doPlayerRemoveMoney(cid, totalCost)
            self.npcHandler.talkStart[cid] = os.time()
            return true
        end
    end

    -- Callback onSell() function. If you wish, you can change certain Npc to use your onSell().
    function ShopModule:callbackOnSell(cid, itemid, subType, amount, ignoreEquipped, _)
        local shopItem = self:getShopItem(itemid, subType)
        if shopItem == nil then
            error("[ShopModule.onSell] items[itemid] == nil")
            return false
        end

        if shopItem.sell == -1 then
            error("[ShopModule.onSell] attempt to sell a non-sellable item")
            return false
        end

        local parseInfo = {
            [TAG_PLAYERNAME] = getPlayerName(cid),
            [TAG_ITEMCOUNT] = amount,
            [TAG_TOTALCOST] = amount * shopItem.sell,
            [TAG_ITEMNAME] = shopItem.name
        }

        if not isItemFluidContainer(itemid) then
            subType = -1
        end

        if doPlayerRemoveItem(cid, itemid, amount, subType, ignoreEquipped) then
            local msg = self.npcHandler:getMessage(MESSAGE_SOLD)
            msg = self.npcHandler:parseMessage(msg, parseInfo)
            doPlayerSendTextMessage(cid, MESSAGE_INFO_DESCR, msg)
            doPlayerAddMoney(cid, amount * shopItem.sell)
            self.npcHandler.talkStart[cid] = os.time()
            return true
        else
            local msg = self.npcHandler:getMessage(MESSAGE_NEEDITEM)
            msg = self.npcHandler:parseMessage(msg, parseInfo)
            doPlayerSendCancel(cid, msg)
            self.npcHandler.talkStart[cid] = os.time()
            return false
        end
    end

    -- Callback for requesting a trade window with the NPC.
    function ShopModule.requestTrade(cid, message, keywords, parameters, node)
        local module = parameters.module
        if not module.npcHandler:isFocused(cid) then
            return false
        end

        if not module.npcHandler:onTradeRequest(cid) then
            return false
        end

        local itemWindow = {}
        for i = 1, #module.npcHandler.shopItems do
            itemWindow[#itemWindow + 1] = module.npcHandler.shopItems[i]
        end

        if itemWindow[1] == nil then
            local parseInfo = { [TAG_PLAYERNAME] = getPlayerName(cid) }
            local msg = module.npcHandler:parseMessage(module.npcHandler:getMessage(MESSAGE_NOSHOP), parseInfo)
            module.npcHandler:say(msg, cid)
            return true
        end

        local parseInfo = { [TAG_PLAYERNAME] = getPlayerName(cid) }
        local msg = module.npcHandler:parseMessage(module.npcHandler:getMessage(MESSAGE_SENDTRADE), parseInfo)
        openShopWindow(cid, itemWindow,
            function(cid, itemid, subType, amount, ignoreCap, inBackpacks) module.npcHandler:onBuy(cid, itemid, subType, amount, ignoreCap, inBackpacks) end,
            function(cid, itemid, subType, amount, ignoreCap, inBackpacks) module.npcHandler:onSell(cid, itemid, subType, amount, ignoreCap, inBackpacks) end)
        module.npcHandler:say(msg, cid)
        return true
    end

    -- onConfirm keyword callback function. Sells/buys the actual item.
    function ShopModule.onConfirm(cid, message, keywords, parameters, node)
        local module = parameters.module
        if not module.npcHandler:isFocused(cid) or shop_npcuid[cid] ~= getNpcCid() then
            return false
        end
        shop_npcuid[cid] = 0

        local parentParameters = node:getParent():getParameters()
        local parseInfo = {
            [TAG_PLAYERNAME] = getPlayerName(cid),
            [TAG_ITEMCOUNT] = shop_amount[cid],
            [TAG_TOTALCOST] = shop_cost[cid] * shop_amount[cid],
            [TAG_ITEMNAME] = shop_rlname[cid]
        }

        if shop_eventtype[cid] == SHOPMODULE_SELL_ITEM then
            local ret = doPlayerSellItem(cid, shop_itemid[cid], shop_amount[cid], shop_cost[cid] * shop_amount[cid])
            if ret == true then
                local msg = module.npcHandler:getMessage(MESSAGE_ONSELL)
                msg = module.npcHandler:parseMessage(msg, parseInfo)
                module.npcHandler:say(msg, cid)
            else
                local msg = module.npcHandler:getMessage(MESSAGE_MISSINGITEM)
                msg = module.npcHandler:parseMessage(msg, parseInfo)
                module.npcHandler:say(msg, cid)
            end
        elseif shop_eventtype[cid] == SHOPMODULE_BUY_ITEM then
            local cost = shop_cost[cid] * shop_amount[cid]
            if getPlayerMoney(cid) < cost then
                local msg = module.npcHandler:getMessage(MESSAGE_MISSINGMONEY)
                msg = module.npcHandler:parseMessage(msg, parseInfo)
                module.npcHandler:say(msg, cid)
                return false
            end

            local a, b = doNpcSellItem(cid, shop_itemid[cid], shop_amount[cid], shop_subtype[cid], false, false, 1988)
            if a < shop_amount[cid] then
                local msgId = MESSAGE_NEEDMORESPACE
                if a == 0 then
                    msgId = MESSAGE_NEEDSPACE
                end

                local msg = module.npcHandler:getMessage(msgId)
                msg = module.npcHandler:parseMessage(msg, parseInfo)
                module.npcHandler:say(msg, cid)
                if a > 0 then
                    doPlayerRemoveMoney(cid, a * shop_cost[cid])
                    if shop_itemid[cid] == ITEM_PARCEL then
                        doNpcSellItem(cid, ITEM_LABEL, shop_amount[cid], shop_subtype[cid], true, false, 1988)
                    end
                    return true
                end
                return false
            else
                local msg = module.npcHandler:getMessage(MESSAGE_ONBUY)
                msg = module.npcHandler:parseMessage(msg, parseInfo)
                module.npcHandler:say(msg, cid)
                doPlayerRemoveMoney(cid, cost)
                if shop_itemid[cid] == ITEM_PARCEL then
                    doNpcSellItem(cid, ITEM_LABEL, shop_amount[cid], shop_subtype[cid], true, false, 1988)
                end
                return true
            end
        elseif shop_eventtype[cid] == SHOPMODULE_BUY_ITEM_CONTAINER then
            local ret = doPlayerBuyItemContainer(cid, shop_container[cid], shop_itemid[cid], shop_amount[cid], shop_cost[cid] * shop_amount[cid], shop_subtype[cid])
            if ret == true then
                local msg = module.npcHandler:getMessage(MESSAGE_ONBUY)
                msg = module.npcHandler:parseMessage(msg, parseInfo)
                module.npcHandler:say(msg, cid)
            else
                local msg = module.npcHandler:getMessage(MESSAGE_MISSINGMONEY)
                msg = module.npcHandler:parseMessage(msg, parseInfo)
                module.npcHandler:say(msg, cid)
            end
        end

        module.npcHandler:resetNpc(cid)
        return true
    end

    -- onDecline keyword callback function. Generally called when the player sais "no" after wanting to buy an item.
    function ShopModule.onDecline(cid, message, keywords, parameters, node)
        local module = parameters.module
        if not module.npcHandler:isFocused(cid) or shop_npcuid[cid] ~= getNpcCid() then
            return false
        end
        shop_npcuid[cid] = 0

        local parentParameters = node:getParent():getParameters()
        local parseInfo = {
            [TAG_PLAYERNAME] = getPlayerName(cid),
            [TAG_ITEMCOUNT] = shop_amount[cid],
            [TAG_TOTALCOST] = shop_cost[cid] * shop_amount[cid],
            [TAG_ITEMNAME] = shop_rlname[cid]
        }

        local msg = module.npcHandler:parseMessage(module.noText, parseInfo)
        module.npcHandler:say(msg, cid)
        module.npcHandler:resetNpc(cid)
        return true
    end

    -- tradeItem callback function. Makes the npc say the message defined by MESSAGE_BUY or MESSAGE_SELL
    function ShopModule.tradeItem(cid, message, keywords, parameters, node)
        local module = parameters.module
        if not module.npcHandler:isFocused(cid) then
            return false
        end

        if not module.npcHandler:onTradeRequest(cid) then
            return true
        end

        local count = module:getCount(message)
        module.amount = count

        shop_amount[cid] = module.amount
        shop_cost[cid] = parameters.cost
        shop_rlname[cid] = parameters.realName
        shop_itemid[cid] = parameters.itemid
        shop_container[cid] = parameters.container
        shop_npcuid[cid] = getNpcCid()
        shop_eventtype[cid] = parameters.eventType
        shop_subtype[cid] = parameters.subType

        local parseInfo = {
            [TAG_PLAYERNAME] = getPlayerName(cid),
            [TAG_ITEMCOUNT] = shop_amount[cid],
            [TAG_TOTALCOST] = shop_cost[cid] * shop_amount[cid],
            [TAG_ITEMNAME] = shop_rlname[cid]
        }

        if shop_eventtype[cid] == SHOPMODULE_SELL_ITEM then
            local msg = module.npcHandler:getMessage(MESSAGE_SELL)
            msg = module.npcHandler:parseMessage(msg, parseInfo)
            module.npcHandler:say(msg, cid)
        elseif shop_eventtype[cid] == SHOPMODULE_BUY_ITEM then
            local msg = module.npcHandler:getMessage(MESSAGE_BUY)
            msg = module.npcHandler:parseMessage(msg, parseInfo)
            module.npcHandler:say(msg, cid)
        elseif shop_eventtype[cid] == SHOPMODULE_BUY_ITEM_CONTAINER then
            local msg = module.npcHandler:getMessage(MESSAGE_BUY)
            msg = module.npcHandler:parseMessage(msg, parseInfo)
            module.npcHandler:say(msg, cid)
        end
        return true
    end
 
    function VoiceModule:new(voices, timeout, chance)
    local obj = {}
    setmetatable(obj, self)
    self.__index = self

    obj.voices = voices
    for i = 1, #obj.voices do
        local voice = obj.voices[i]
        if voice.yell then
            voice.yell = nil
            voice.talktype = TALKTYPE_YELL
        else
            voice.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
 
end

errors

You didn't copy everything.
You forgot this;
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
        local voice = obj.voices[i]
        if voice.yell then
            voice.yell = nil
            voice.talktype = TALKTYPE_YELL
        else
            voice.talktype = TALKTYPE_SAY
        end
    end

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