• 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!

TFS 1.X+ Name Changer NPC Script

Dip Set

Veteran OT User
Joined
Dec 27, 2007
Messages
405
Solutions
2
Reaction score
369
Using TFS 1.3+
My Script:

Lua:
local keywordHandler = KeywordHandler:new()
local npcHandler = NpcHandler:new(keywordHandler)
NpcSystem.parseParameters(npcHandler)
local talk = {}
local name = {}

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
function onPlayerEndTrade(cid) npcHandler:onPlayerEndTrade(cid) end
function onPlayerCloseChannel(cid) npcHandler:onPlayerCloseChannel(cid) end

function creatureGreetCallback(cid)
talk[cid] = 0
name[cid] = ''
return true
end

local chars = {' ', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'}

local forbiddenWords = {'gm', 'tutor', 'god', 'cm', 'admin', 'owner'}
local maxWords = 3
local maxLength = 20
local minChars = 4

RET_VALID = 1
RET_EXISTS = 2
RET_INVALID = 3

local function wordCount(str)
local count = 0
  for word in string.gmatch(str, "%a+") do
count = count + 1
end
  return count
end

local function validLen(s)
  for i in string.gmatch(s, "%a+") do
  if i:len() < minChars then
  return false
  end
  end
  return true
end

local function validName(name)
if getPlayerGUIDByName(name) ~= nil then
return RET_EXISTS
end

for i = 1, name:len() do
if not(isInArray(chars, name:sub(i,i))) or isInArray(forbiddenWords, name:sub(i, i)) or wordCount(name) > maxWords or name:len() > maxLength or string.find(name, "  ") or not validLen(name) then
return RET_INVALID
end
end
return RET_VALID
end

local function getValid(name, opt)
local function tchelper(first, rest)
return first:upper()..rest:lower()
end

return opt and name:gsub("(%a)([%w_']*)", tchelper) or name:gsub("^%l", string.upper)
end

local config = {
  type = 'item', -- or 'item'
  money = 0, -- = 1cc
  item = {6527, 1}, --item id, count
  everyFirstLetterCapital = true
}

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

if msgcontains(msg, "change") and talk[cid] == 0 then
selfSay("Whats your new name?", cid)
talk[cid] = 1
elseif talk[cid] == 1 then
local v = getValid(msg:lower(), config.everyFirstLetterCapital)
local ret = validName(v)
if ret == RET_VALID then
selfSay("New name:'" .. v .. "' for " .. (config.type == "money" and (config.money .. " gold") or (config.item[2] .. ' ' .. (config.item[2] > 1 and getItemPluralNameById(config.item[1]) or getItemNameById(config.item[1])))) .. "?", cid)
talk[cid], name[cid] = 2, v
else
if ret == RET_INVALID then
selfSay(msg .. " Its a invalid name. Whats your new name?", cid)
elseif ret == RET_EXISTS then
selfSay(msg .. " this name already exists. Whats your new name?", cid)
end
end
elseif talk[cid] == 2 then
if msgcontains(msg, "yes") then
if (config.type == 'money' and doPlayerRemoveMoney(cid, config.money)) or (config.type ~= 'money' and doPlayerRemoveItem(cid, config.item[1], config.item[2])) then
local curName = getPlayerName(cid)
doRemoveCreature(cid)
db.executeQuery("UPDATE players SET name = '"..name[cid].."' WHERE name = '"..curName.."';")
else
selfSay("You dont have " .. (config.type == "money" and (config.money .. " gold") or (config.item[2] .. ' ' .. (config.item[2] > 1 and getItemPluralNameById(config.item[1]) or getItemNameById(config.item[1])))) .. "!", cid)
talk[cid] = 0
end
else
selfSay("Im not available right now, maybe later.", cid)
talk[cid] = 0
end
end


return true
end

npcHandler:setMessage(MESSAGE_FAREWELL, "Bye!")
npcHandler:setMessage(MESSAGE_WALKAWAY, "Go away!")
npcHandler:setCallback(CALLBACK_MESSAGE_DEFAULT, messageDefaultCallback)
npcHandler:setCallback(CALLBACK_FAREWELL, creatureFarewell)
npcHandler:setCallback(CALLBACK_CREATURE_DISAPPEAR, creatureFarewell)
npcHandler:setCallback(CALLBACK_GREET, creatureGreetCallback)
npcHandler:addModule(FocusModule:new())

Problem number 1:
Lua:
local function validName(name)

if getPlayerGUIDByName(name) ~= nil then

return RET_EXISTS

end
The Problem: getPlayerGUIDByName(name) does not function properly, it is always returning RET_EXISTS, maybe the issue is getPlayerGUIDByName is pulling ID for the current players name instead of searching for the "new" name?
For example:
NPC: What new name do you want?
Sorcy: Sorcynewname
--Script: Is there already an Id for player with name Sorcy?--
--Script: Yes there is, RET_EXISTS--
NPC: That name is already taken!

My Compat.lua has:
Lua:
function getPlayerGUIDByName(name)
    local player = Player(name)
    if player ~= nil then
        return player:getGuid()
    end

    local resultId = db.storeQuery("SELECT `id` FROM `players` WHERE `name` = " .. db.escapeString(name))
    if resultId ~= false then
        local guid = result.getDataInt(resultId, "id")
        result.free(resultId)
        return guid
    end
    return 0
end










Problem number 2: Even if I comment those lines out for RET_EXISTS, so the script "thinks" that name doesn't exist, then executeQuery returns nil.
Lua:
attempt to call field 'executeQuery' (a nil value)

This is the line specifically that returns nil
Lua:
db.executeQuery("UPDATE players SET name = '"..name[cid].."' WHERE name = '"..curName.."';")
I believe it is an issue with either name[cid] or curName, because when I push the sqlQuery manually, it works.
Image 1 shows my players column, showing id and name are being used.

1591882556642.png
Image 2 shows my sqlQuery just like in the db.executeQuery line

1591882802281.png
Image 3 shows the sqlQuery functions properly if the names are correct.
1591882819225.png

Sorry for such a long post, I tried to make it as detailed as possible, when the final script is working properly, I will of course post it for the community. This is a name changer NPC script, you pay him money or an item, give him new name, and he will perform name change for you.
 
Solution
Changed:
if getPlayerGUIDByName(name) ~= nil then
to
if getPlayerDatabaseInfo(name) then
(Remember to add the function @Evil Puncker linked).

Changed:
db.executeQuery to db.query

And escaped the names in the query to stop sql injection hacks:
Lua:
db.query("UPDATE players SET name = "..db.escapeString(name[cid]).." WHERE name = "..db.escapeString(curName)..";")

Fixed indentation.

Lua:
local keywordHandler = KeywordHandler:new()
local npcHandler = NpcHandler:new(keywordHandler)
NpcSystem.parseParameters(npcHandler)
local talk = {}
local name = {}

function onCreatureAppear(cid) npcHandler:onCreatureAppear(cid) end
function onCreatureDisappear(cid) npcHandler:onCreatureDisappear(cid) end
function...
Changed:
if getPlayerGUIDByName(name) ~= nil then
to
if getPlayerDatabaseInfo(name) then
(Remember to add the function @Evil Puncker linked).

Changed:
db.executeQuery to db.query

And escaped the names in the query to stop sql injection hacks:
Lua:
db.query("UPDATE players SET name = "..db.escapeString(name[cid]).." WHERE name = "..db.escapeString(curName)..";")

Fixed indentation.

Lua:
local keywordHandler = KeywordHandler:new()
local npcHandler = NpcHandler:new(keywordHandler)
NpcSystem.parseParameters(npcHandler)
local talk = {}
local name = {}

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
function onPlayerEndTrade(cid) npcHandler:onPlayerEndTrade(cid) end
function onPlayerCloseChannel(cid) npcHandler:onPlayerCloseChannel(cid) end

function creatureGreetCallback(cid)
    talk[cid] = 0
    name[cid] = ''
    return true
end

local chars = {
    ' ', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 
    'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 
    'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 
    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 
    'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 
    'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
}

local forbiddenWords = {'gm', 'tutor', 'god', 'cm', 'admin', 'owner'}
local maxWords = 3
local maxLength = 20
local minChars = 4

RET_VALID = 1
RET_EXISTS = 2
RET_INVALID = 3

local function wordCount(str)
    local count = 0
    for word in string.gmatch(str, "%a+") do
        count = count + 1
    end
    return count
end

local function validLen(s)
  for i in string.gmatch(s, "%a+") do
      if i:len() < minChars then
          return false
      end
  end
  return true
end

local function validName(name)
    if getPlayerDatabaseInfo(name) then
        return RET_EXISTS
    end

    for i = 1, name:len() do
        if not(isInArray(chars, name:sub(i,i))) or isInArray(forbiddenWords, name:sub(i, i)) or wordCount(name) > maxWords or name:len() > maxLength or string.find(name, "  ") or not validLen(name) then
            return RET_INVALID
        end
    end
    return RET_VALID
end

local function getValid(name, opt)
    local function tchelper(first, rest)
        return first:upper()..rest:lower()
    end
    return opt and name:gsub("(%a)([%w_']*)", tchelper) or name:gsub("^%l", string.upper)
end

local config = {
  type = 'item', -- or 'item'
  money = 0, -- = 1cc
  item = {6527, 1}, --item id, count
  everyFirstLetterCapital = true
}

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

    if msgcontains(msg, "change") and talk[cid] == 0 then
        selfSay("Whats your new name?", cid)
        talk[cid] = 1
    elseif talk[cid] == 1 then
        local v = getValid(msg:lower(), config.everyFirstLetterCapital)
        local ret = validName(v)
        if ret == RET_VALID then
            selfSay("New name:'" .. v .. "' for " .. (config.type == "money" and (config.money .. " gold") or (config.item[2] .. ' ' .. (config.item[2] > 1 and getItemPluralNameById(config.item[1]) or getItemNameById(config.item[1])))) .. "?", cid)
            talk[cid], name[cid] = 2, v
        else
            if ret == RET_INVALID then
                selfSay(msg .. " Its a invalid name. Whats your new name?", cid)
            elseif ret == RET_EXISTS then
                selfSay(msg .. " this name already exists. Whats your new name?", cid)
            end
        end
    elseif talk[cid] == 2 then
        if msgcontains(msg, "yes") then
            if (config.type == 'money' and doPlayerRemoveMoney(cid, config.money)) or (config.type ~= 'money' and doPlayerRemoveItem(cid, config.item[1], config.item[2])) then
                local curName = getPlayerName(cid)
                doRemoveCreature(cid)
                db.query("UPDATE players SET name = "..db.escapeString(name[cid]).." WHERE name = "..db.escapeString(curName)..";")
            else
                selfSay("You dont have " .. (config.type == "money" and (config.money .. " gold") or (config.item[2] .. ' ' .. (config.item[2] > 1 and getItemPluralNameById(config.item[1]) or getItemNameById(config.item[1])))) .. "!", cid)
                talk[cid] = 0
            end
        else
            selfSay("Im not available right now, maybe later.", cid)
            talk[cid] = 0
        end
    end
    return true
end

npcHandler:setMessage(MESSAGE_FAREWELL, "Bye!")
npcHandler:setMessage(MESSAGE_WALKAWAY, "Go away!")
npcHandler:setCallback(CALLBACK_MESSAGE_DEFAULT, messageDefaultCallback)
npcHandler:setCallback(CALLBACK_FAREWELL, creatureFarewell)
npcHandler:setCallback(CALLBACK_CREATURE_DISAPPEAR, creatureFarewell)
npcHandler:setCallback(CALLBACK_GREET, creatureGreetCallback)
npcHandler:addModule(FocusModule:new())
 
Solution
No I found it on forums. Installation process is exactly what evil puncker/znote said, just make npc and done
 
Thanks for the info :D

I wonder would it be possible to make something like this for gender change also? Perhaps even merge the two.
 
Back
Top