• 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 NPCs mixing player requests

guiismiti

Well-Known Member
Joined
May 19, 2014
Messages
315
Solutions
3
Reaction score
68
Hello,

I'm having a problem with an NPC.
The original code is too long, so, I cut most of the generalConfig array and the entire addonItemsIds array.
The code is working, but the value of config gets mixed when two players talk to the NPC.

Code:
local generalConfig = {
    ["citizen"] = {
        id = {male = 128, female = 136},
        items = {
            {addonItemsIds.minotaurLeather, 100},
            {addonItemsIds.chickenFeather, 100},
            {addonItemsIds.honeyComb, 50},
            {addonItemsIds.legionHelmet, 1}
        }
    },
    ["hunter"] = {
        id = {male = 129, female = 137},
        items = {
            {addonItemsIds.lizardLeather, 100},
            {addonItemsIds.redDragonLeather, 100},
            {addonItemsIds.enchantedChickenWing, 5},
            {addonItemsIds.pieceOfRoyalSteel, 1},
            {addonItemsIds.pieceOfDraconianSteel, 1},
            {addonItemsIds.pieceOfHellSteel, 1},
            {addonItemsIds.sniperGloves, 1}
        }
    }
}

local config

local function creatureSayCallback(cid, type, msg)
    if not npcHandler:isFocused(cid) then
        return false
    end
  
    local player = Player(cid)
    local answer
  
    msg = msg:lower()
  
    if msg == "valdisnei" then
        npcHandler:say("Valdisnei sells items for addons. He is at the Yalahar Palace.", cid)
        npcHandler.topic[cid] = 0
    elseif ((msg == "addon") or (msg == "addons")) then
        answer = "And which addons would you like? I can offer you "
      
        for outfitName, configs in pairs(generalConfig) do
            answer = answer .. "{" .. outfitName .. "}"
          
            if outfitName ~= "assassin" then
                answer = answer .. ", "
            else
                answer = answer .. "."
            end
        end
      
        npcHandler:say(answer, cid)
        npcHandler.topic[cid] = 1
    elseif npcHandler.topic[cid] == 1 then
        -- player has chosen an outfit
        config = generalConfig[msg]
      
        -- change mage for summoner and summoner for mage if player is female
        if ((msg == "mage") and (player:getSex() == 1)) then
            config = generalConfig["summoner"]
        elseif ((msg == "summoner") and (player:getSex() == 1)) then
            config = generalConfig["mage"]
        end
      
        if config then
            answer = "For this addon, I need "
          
            for i = 1, #config.items do
                local itemType = ItemType(config.items[i][1])
                answer = answer .. (i ~= 1 and (i == #config.items and " and " or ", ") or "") .. (config.items[i][2] > 1 and config.items[i][2] or itemType:getArticle()) .. " " .. (config.items[i][2] > 1 and itemType:getPluralName() or itemType:getName())
            end
          
            answer = answer .. ". Do you have it?"
          
            npcHandler:say(answer, cid)
            npcHandler.topic[cid] = 2
        else
            npcHandler:say("That is not a valid outfit.", cid)
            npcHandler.topic[cid] = 0
        end
    elseif npcHandler.topic[cid] == 2 then
        if msg == "yes" then
            -- check if player already has outfit
            if not player:hasOutfit(config.id.male, 3) then
                -- check if player has items
                local hasItems = true
              
                for i = 1, #config.items do
                    if player:getItemCount(config.items[i][1]) < config.items[i][2] then
                        hasItems = false
                    end
                end
              
                if hasItems then
                    -- remove items
                    for i = 1, #config.items do
                        player:removeItem(config.items[i][1], config.items[i][2])
                    end
                  
                    -- give addon
                    player:addOutfitAddon(config.id.male, 3)
                    player:addOutfitAddon(config.id.female, 3)
                  
                    npcHandler:say("Congratulation! Enjoy your new addon.", cid)
                else
                    npcHandler:say("You do not have the items with you.", cid)
                end
              
                npcHandler.topic[cid] = 0
            else
                npcHandler:say("You already have this addon.", cid)
                npcHandler.topic[cid] = 0
            end
        else
            npcHandler:say("Okay then.", cid)
            npcHandler.topic[cid] = 0
        end
    end
  
    return true
end

The problem (example):
- Player #1 says hi, addon, brotherhood
- This will define config as generalConfig["brotherhood"]
- If Player #2 says hi, addon, barbarian, it will not only set a value for config for Player #2, it will also change the value of config of Player #1 to generalConfig["barbarian"]

Can anybody help me?


EDITED: I tried placing "local config" inside the main function, but its value gets lost. I've also tried to use config as non local, but it also mixes the values between players.
 
I'm taking a look at other NPCs and I noticed that they use config[cid] instead of config.
Is that the best solution or the common practice?
 
Hello,

I'm having a problem with an NPC.
The original code is too long, so, I cut most of the generalConfig array and the entire addonItemsIds array.
The code is working, but the value of config gets mixed when two players talk to the NPC.

Code:
local generalConfig = {
    ["citizen"] = {
        id = {male = 128, female = 136},
        items = {
            {addonItemsIds.minotaurLeather, 100},
            {addonItemsIds.chickenFeather, 100},
            {addonItemsIds.honeyComb, 50},
            {addonItemsIds.legionHelmet, 1}
        }
    },
    ["hunter"] = {
        id = {male = 129, female = 137},
        items = {
            {addonItemsIds.lizardLeather, 100},
            {addonItemsIds.redDragonLeather, 100},
            {addonItemsIds.enchantedChickenWing, 5},
            {addonItemsIds.pieceOfRoyalSteel, 1},
            {addonItemsIds.pieceOfDraconianSteel, 1},
            {addonItemsIds.pieceOfHellSteel, 1},
            {addonItemsIds.sniperGloves, 1}
        }
    }
}

local config

local function creatureSayCallback(cid, type, msg)
    if not npcHandler:isFocused(cid) then
        return false
    end
 
    local player = Player(cid)
    local answer
 
    msg = msg:lower()
 
    if msg == "valdisnei" then
        npcHandler:say("Valdisnei sells items for addons. He is at the Yalahar Palace.", cid)
        npcHandler.topic[cid] = 0
    elseif ((msg == "addon") or (msg == "addons")) then
        answer = "And which addons would you like? I can offer you "
    
        for outfitName, configs in pairs(generalConfig) do
            answer = answer .. "{" .. outfitName .. "}"
        
            if outfitName ~= "assassin" then
                answer = answer .. ", "
            else
                answer = answer .. "."
            end
        end
    
        npcHandler:say(answer, cid)
        npcHandler.topic[cid] = 1
    elseif npcHandler.topic[cid] == 1 then
        -- player has chosen an outfit
        config = generalConfig[msg]
    
        -- change mage for summoner and summoner for mage if player is female
        if ((msg == "mage") and (player:getSex() == 1)) then
            config = generalConfig["summoner"]
        elseif ((msg == "summoner") and (player:getSex() == 1)) then
            config = generalConfig["mage"]
        end
    
        if config then
            answer = "For this addon, I need "
        
            for i = 1, #config.items do
                local itemType = ItemType(config.items[i][1])
                answer = answer .. (i ~= 1 and (i == #config.items and " and " or ", ") or "") .. (config.items[i][2] > 1 and config.items[i][2] or itemType:getArticle()) .. " " .. (config.items[i][2] > 1 and itemType:getPluralName() or itemType:getName())
            end
        
            answer = answer .. ". Do you have it?"
        
            npcHandler:say(answer, cid)
            npcHandler.topic[cid] = 2
        else
            npcHandler:say("That is not a valid outfit.", cid)
            npcHandler.topic[cid] = 0
        end
    elseif npcHandler.topic[cid] == 2 then
        if msg == "yes" then
            -- check if player already has outfit
            if not player:hasOutfit(config.id.male, 3) then
                -- check if player has items
                local hasItems = true
            
                for i = 1, #config.items do
                    if player:getItemCount(config.items[i][1]) < config.items[i][2] then
                        hasItems = false
                    end
                end
            
                if hasItems then
                    -- remove items
                    for i = 1, #config.items do
                        player:removeItem(config.items[i][1], config.items[i][2])
                    end
                
                    -- give addon
                    player:addOutfitAddon(config.id.male, 3)
                    player:addOutfitAddon(config.id.female, 3)
                
                    npcHandler:say("Congratulation! Enjoy your new addon.", cid)
                else
                    npcHandler:say("You do not have the items with you.", cid)
                end
            
                npcHandler.topic[cid] = 0
            else
                npcHandler:say("You already have this addon.", cid)
                npcHandler.topic[cid] = 0
            end
        else
            npcHandler:say("Okay then.", cid)
            npcHandler.topic[cid] = 0
        end
    end
 
    return true
end

The problem (example):
- Player #1 says hi, addon, brotherhood
- This will define config as generalConfig["brotherhood"]
- If Player #2 says hi, addon, barbarian, it will not only set a value for config for Player #2, it will also change the value of config of Player #1 to generalConfig["barbarian"]

Can anybody help me?


EDITED: I tried placing "local config" inside the main function, but its value gets lost. I've also tried to use config as non local, but it also mixes the values between players.
could you put it on pastebin.com so i can look at the full script
 
Try to store answer choice in a different table:
Code:
CURRENT_OUTFIT = {}

Replace this line:
Code:
config = generalConfig[msg]
with
Code:
CURRENT_OUTFIT[player:getGuid()] = msg

Then any time in the process that it needs to remember what the outfit it was:
Code:
local curOutfit = generalConfig[CURRENT_OUTFIT[player:getGuid()]]
print(curOutfit.id.male) == 128 (for example if the player said citizen)
 
Full code.
I fixed this and some other NPCs I had edited.
I found that solution (the one I mentioned earlier) in Znozel.lua
About this code - the previous script for my addons NPC was extremely messy, so I decided to remake it completely.
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

local addonItemsIds = {
    minotaurLeather = 5878,
    chickenFeather = 5890,
    honeyComb = 5902,
    legionHelmet = 2480,
    lizardLeather = 5876,
    redDragonLeather = 5948,
    enchantedChickenWing = 5891,
    pieceOfRoyalSteel = 5887,
    pieceOfDraconianSteel = 5889,
    pieceOfHellSteel = 5888,
    sniperGloves = 5875,
    wandOfVortex = 2190,
    wandOfDragonbreath = 2191,
    wandOfDecay = 2188,
    wandOfCosmicEnergy = 2189,
    wandOfInferno = 2187,
    snakebiteRod = 2182,
    moonlightRod = 2186,
    necroticRod = 2185,
    terraRod = 2181,
    hailstormRod = 2183,
    magicSulphur = 5904,
    ankh = 2193,
    soulStone = 5809,
    ferumbrasHat = 5903,
    ironOre = 5880,
    hugeChunkOfCrudeIron = 5892,
    perfectBehemothFang = 5893,
    damagedSteelHelmet = 5924,
    flaskOfWarriorSweat = 5885,
    winningLotteryTicket = 5958,
    batWing = 5894,
    redPieceOfCloth = 5911,
    apeFur = 5883,
    holyOrchid = 5922,
    spiderSilk = 5879,
    lizardScale = 5881,
    redDragonScale = 5882,
    vampireDust = 5905,
    hardenedBones = 5925,
    turtleShell = 5899,
    spiritContainer = 5884,
    dragonClaw = 5919,
    greenPieceOfCloth = 5910,
    bearPaw = 5896,
    wolfPaw = 5897,
    demonDust = 5906,
    medusaShield = 2536,
    dragonScaleMail = 2492,
    crownLegs = 2488,
    ringOfTheSky = 2123,
    coralComb = 5945,
    fishFin = 5895,
    bluePieceOfCloth = 5912,
    eyePatch = 6098,
    pegLeg = 6126,
    hook = 6097,
    ronTheRipperSabre = 6101,
    deadeyeDeviousEyePatch = 6102,
    lethalLissyShirt = 6100,
    brutusBloodbeardHat = 6099,
    brownPieceOfCloth = 5913,
    yellowPieceOfCloth = 5914,
    whitePieceOfCloth = 5909,
    behemothClaw = 5930,
    noseRing = 5804,
    simonStaff = 6107,
    pirateVoodooDoll = 5810,
    voodooDoll = 3955,
    mandrake = 5015,
    bananaStaff = 3966,
    tribalMask = 3967,
    demonicEssence = 6500,
    smallGoldenAnchor = 15432,
    tanjisSight = 15435,
    obujosShell = 15436,
    jaulPearl = 15434,
    mageCap = 13756,
    elementalSpikes = 13940
}

local generalConfig = {
    ["citizen"] = {
        id = {male = 128, female = 136},
        items = {
            {addonItemsIds.minotaurLeather, 100},
            {addonItemsIds.chickenFeather, 100},
            {addonItemsIds.honeyComb, 50},
            {addonItemsIds.legionHelmet, 1}
        }
    },
    ["hunter"] = {
        id = {male = 129, female = 137},
        items = {
            {addonItemsIds.lizardLeather, 100},
            {addonItemsIds.redDragonLeather, 100},
            {addonItemsIds.enchantedChickenWing, 5},
            {addonItemsIds.pieceOfRoyalSteel, 1},
            {addonItemsIds.pieceOfDraconianSteel, 1},
            {addonItemsIds.pieceOfHellSteel, 1},
            {addonItemsIds.sniperGloves, 1}
        }
    },
    ["mage"] = {
        id = {male = 130, female = 141},
        items = {
            {addonItemsIds.wandOfVortex, 1},
            {addonItemsIds.wandOfDragonbreath, 1},
            {addonItemsIds.wandOfDecay, 1},
            {addonItemsIds.wandOfCosmicEnergy, 1},
            {addonItemsIds.wandOfInferno, 1},
            {addonItemsIds.snakebiteRod, 1},
            {addonItemsIds.moonlightRod, 1},
            {addonItemsIds.necroticRod, 1},
            {addonItemsIds.terraRod, 1},
            {addonItemsIds.hailstormRod, 1},
            {addonItemsIds.magicSulphur, 10},
            {addonItemsIds.ankh, 20},
            {addonItemsIds.soulStone, 1},
            {addonItemsIds.ferumbrasHat, 1}
        }
    },
    ["knight"] = {
        id = {male = 131, female = 139},
        items = {
            {addonItemsIds.ironOre, 100},
            {addonItemsIds.hugeChunkOfCrudeIron, 1},
            {addonItemsIds.perfectBehemothFang, 100},
            {addonItemsIds.damagedSteelHelmet, 1},
            {addonItemsIds.flaskOfWarriorSweat, 1},
            {addonItemsIds.pieceOfRoyalSteel, 1}
        }
    },
    ["summoner"] = {
        id = {male = 133, female = 138},
        items = {
            {addonItemsIds.winningLotteryTicket, 1},
            {addonItemsIds.batWing, 70},
            {addonItemsIds.redPieceOfCloth, 20},
            {addonItemsIds.apeFur, 40},
            {addonItemsIds.holyOrchid, 35},
            {addonItemsIds.spiderSilk, 100},
            {addonItemsIds.lizardScale, 60},
            {addonItemsIds.redDragonScale, 40},
            {addonItemsIds.magicSulphur, 15},
            {addonItemsIds.vampireDust, 30}
        }
    },
    ["warrior"] = {
        id = {male = 134, female = 142},
        items = {
            {addonItemsIds.hardenedBones, 100},
            {addonItemsIds.turtleShell, 100},
            {addonItemsIds.spiritContainer, 1},
            {addonItemsIds.dragonClaw, 1},
            {addonItemsIds.ironOre, 100},
            {addonItemsIds.pieceOfRoyalSteel, 1}
        }
    },
    ["barbarian"] = {
        id = {male = 143, female = 147},
        items = {
            {addonItemsIds.spiritContainer, 1},
            {addonItemsIds.flaskOfWarriorSweat, 1},
            {addonItemsIds.redPieceOfCloth, 50},
            {addonItemsIds.greenPieceOfCloth, 50},
            {addonItemsIds.spiderSilk, 100},
            {addonItemsIds.ironOre, 100},
            {addonItemsIds.hugeChunkOfCrudeIron, 1},
            {addonItemsIds.perfectBehemothFang, 50},
            {addonItemsIds.lizardLeather, 50}
        }
    },
    ["druid"] = {
        id = {male = 144, female = 148},
        items = {
            {addonItemsIds.bearPaw, 50},
            {addonItemsIds.wolfPaw, 50},
            {addonItemsIds.demonDust, 100}
        }
    },
    ["wizard"] = {
        id = {male = 145, female = 149},
        items = {
            {addonItemsIds.medusaShield, 1},
            {addonItemsIds.dragonScaleMail, 1},
            {addonItemsIds.crownLegs, 1},
            {addonItemsIds.ringOfTheSky, 1},
            {addonItemsIds.holyOrchid, 50}
        }
    },
    ["oriental"] = {
        id = {male = 146, female = 150},
        items = {
            {addonItemsIds.coralComb, 1},
            {addonItemsIds.apeFur, 100},
            {addonItemsIds.fishFin, 100},
            {addonItemsIds.enchantedChickenWing, 2},
            {addonItemsIds.bluePieceOfCloth, 100}
        }
    },
    ["pirate"] = {
        id = {male = 151, female = 155},
        items = {
            {addonItemsIds.eyePatch, 100},
            {addonItemsIds.pegLeg, 100},
            {addonItemsIds.hook, 100},
            {addonItemsIds.ronTheRipperSabre, 1},
            {addonItemsIds.deadeyeDeviousEyePatch, 1},
            {addonItemsIds.lethalLissyShirt, 1},
            {addonItemsIds.brutusBloodbeardHat, 1}
        }
    },
    ["assassin"] = {
        id = {male = 152, female = 156},
        items = {
            {addonItemsIds.bluePieceOfCloth, 50},
            {addonItemsIds.greenPieceOfCloth, 50},
            {addonItemsIds.redPieceOfCloth, 50},
            {addonItemsIds.brownPieceOfCloth, 50},
            {addonItemsIds.yellowPieceOfCloth, 50},
            {addonItemsIds.whitePieceOfCloth, 50},
            {addonItemsIds.spiderSilk, 100},
            {addonItemsIds.behemothClaw, 1},
            {addonItemsIds.noseRing, 1}
        }
    },
    ["beggar"] = {
        id = {male = 153, female = 157},
        items = {
            {addonItemsIds.apeFur, 100},
            {addonItemsIds.simonStaff, 1}
        }
    },
    ["shaman"] = {
        id = {male = 154, female = 158},
        items = {
            {addonItemsIds.pirateVoodooDoll, 5},
            {addonItemsIds.voodooDoll, 5},
            {addonItemsIds.mandrake, 1},
            {addonItemsIds.bananaStaff, 5},
            {addonItemsIds.tribalMask, 5}
        }
    },
    ["nightmare"] = {
        id = {male = 268, female = 269},
        items = {
            {addonItemsIds.demonicEssence, 1500}
        }
    },
    ["brotherhood"] = {
        id = {male = 278, female = 279},
        items = {
            {addonItemsIds.demonicEssence, 1500}
        }
    },
    ["deepling"] = {
        id = {male = 463, female = 464},
        items = {
            {addonItemsIds.smallGoldenAnchor, 1},
            {addonItemsIds.tanjisSight, 1},
            {addonItemsIds.obujosShell, 1},
            {addonItemsIds.jaulPearl, 1}
        }
    },
    ["elementalist"] = {
        id = {male = 432, female = 433},
        items = {
            {addonItemsIds.mageCap, 1},
            {addonItemsIds.elementalSpikes, 1}
        }
    }
}

local config = {}

local function greetCallback(cid)
    local player = Player(cid)
  
    config[cid] = nil
  
    npcHandler:setMessage(MESSAGE_GREET, "Hello |PLAYERNAME|! Are you interested in any {addon}s? You can get the items by hunting or from NPC {Valdisnei}.")
  
    return true
end

local function creatureSayCallback(cid, type, msg)
    if not npcHandler:isFocused(cid) then
        return false
    end
  
    local player = Player(cid)
    local answer
  
    msg = msg:lower()
  
    if msgcontains(msg, "valdisnei") then
        npcHandler:say("Valdisnei sells items for addons. He is at the Yalahar Palace.", cid)
        npcHandler.topic[cid] = 0
    elseif msgcontains(msg, "addon") then
        answer = "And which addons would you like? I can offer you "
      
        for outfitName, configs in pairs(generalConfig) do
            answer = answer .. "{" .. outfitName .. "}"
          
            if outfitName ~= "assassin" then
                answer = answer .. ", "
            else
                answer = answer .. "."
            end
        end
      
        npcHandler:say(answer, cid)
        npcHandler.topic[cid] = 1
    elseif npcHandler.topic[cid] == 1 then
        -- player has chosen an outfit
        config[cid] = generalConfig[msg]
      
        -- change mage for summoner and summoner for mage if player is female
        if ((msgcontains(msg, "mage")) and (player:getSex() == 0)) then
            config[cid] = generalConfig["summoner"]
        elseif ((msgcontains(msg, "summoner")) and (player:getSex() == 0)) then
            config[cid] = generalConfig["mage"]
        end
      
        if config[cid] then
            answer = "For this addon, I need "
          
            for i = 1, #config[cid].items do
                local itemType = ItemType(config[cid].items[i][1])
                answer = answer .. (i ~= 1 and (i == #config[cid].items and " and " or ", ") or "") .. (config[cid].items[i][2] > 1 and config[cid].items[i][2] or itemType:getArticle()) .. " " .. (config[cid].items[i][2] > 1 and itemType:getPluralName() or itemType:getName())
            end
          
            answer = answer .. ". Do you have it?"
          
            npcHandler:say(answer, cid)
            npcHandler.topic[cid] = 2
        else
            npcHandler:say("That is not a valid outfit.", cid)
            npcHandler.topic[cid] = 0
        end
    elseif npcHandler.topic[cid] == 2 then
        if msgcontains(msg, "yes") then
            -- check if player already has outfit
            if not player:hasOutfit(config[cid].id.male, 3) then
                -- check if player has items
                local hasItems = true
              
                for i = 1, #config[cid].items do
                    if player:getItemCount(config[cid].items[i][1]) < config[cid].items[i][2] then
                        hasItems = false
                    end
                end
              
                if hasItems then
                    -- remove items
                    for i = 1, #config[cid].items do
                        player:removeItem(config[cid].items[i][1], config[cid].items[i][2])
                    end
                  
                    -- give addon
                    player:addOutfitAddon(config[cid].id.male, 3)
                    player:addOutfitAddon(config[cid].id.female, 3)
                  
                    npcHandler:say("Congratulation! Enjoy your new addon.", cid)
                else
                    npcHandler:say("You do not have the items with you.", cid)
                end
              
                npcHandler.topic[cid] = 0
            else
                npcHandler:say("You already have this addon.", cid)
                npcHandler.topic[cid] = 0
            end
        else
            npcHandler:say("Okay then.", cid)
            npcHandler.topic[cid] = 0
        end
    end
  
    return true
end

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

npcHandler:setMessage(MESSAGE_FAREWELL, "Farewell.")
npcHandler:setMessage(MESSAGE_WALKAWAY, "Farewell.")
npcHandler:setCallback(CALLBACK_GREET, greetCallback)
 
Back
Top