• 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 Hello folks! How would I go about an alternativ way of adding npc focus?

Sprrw

Well-Known Member
Joined
Jun 22, 2021
Messages
100
Reaction score
55
Location
Sweden
So basically Im looking for ways to enter a npc convo without having to speak. Example: Enter a room and the npc says "Hello, and welcome. Please browse my shop". Idk if thats a super good idea but you kinda get the feel of it. Im asuming this is not doable thorugh a normal moveevent. Would this type of thing require a source edit or should I be able to do it through the npc handler script?

Info: Tfs 1.4

As always, thanks a lot for reading, have an amzing day!
 
Off the top of my head, you can make it work using a moveevent. Probably something like that:

onStepIn > creature:say(). If it's a quest you're talking about, and you don't want the npc to repeat the same message every time a player steps into that floor, you can register a storageID also inside that onStepIn script

Not tested, of course :)
 
Off the top of my head, you can make it work using a moveevent. Probably something like that:

onStepIn > creature:say(). If it's a quest you're talking about, and you don't want the npc to repeat the same message every time a player steps into that floor, you can register a storageID also inside that onStepIn script

Not tested, of course :)
You know what, this aint a bad idea at all. I will give it a go! Thanks a lot m8.
 
you have other callbacks beyond 'onSay' for Npcs. One of them is called onCreatureAppear.
You can also use onThink to check each 200ms if a player is X sqms near your npc.
Both situations are covered inside this list I've made a while ago:
 
you have other callbacks beyond 'onSay' for Npcs. One of them is called onCreatureAppear.
You can also use onThink to check each 200ms if a player is X sqms near your npc.
Both situations are covered inside this list I've made a while ago:
Ohh thats interesting. Ima give it a go. Thanks a lot! Ps, that list is crazy good! For sure bookmarking that thread <3
 
Yeah, scratch my idea, lol, NIght Wolf's seems a lot better. Good luck
Well I actually already went ahead and tested your way out and Im not sure if this is what you meant but I this is what I've got so far :
Lua:
local npcEnterFocus = MoveEvent("npcEnterFocus")

local rightBottomCorner = Position({
    x = 1062,
    y = 970,
    z = 7
})
local leftTopCorner = Position({
    x = 1051,
    y = 961,
    z = 7
})

function npcEnterFocus.onStepIn(creature, item, position, fromPosition)
    if not creature:isPlayer() then
        return true
    end

    local player = creature

    for x = leftTopCorner.x, rightBottomCorner.x do
        for y = leftTopCorner.y, rightBottomCorner.y do
            for z = leftTopCorner.z, rightBottomCorner.z do
                local area = {
                    x = x,
                    y = y,
                    z = z
                }
                local name = "Claire"
                local searchCreature = getTopCreature(area).uid
                if isCreature(searchCreature) and getCreatureName(searchCreature):lower() == name:lower() then
                    local npc = getCreatureName(searchCreature)
                    Creature(searchCreature):say("hello")
                end
            end
        end
    end

    player:teleportTo(fromPosition)
end

npcEnterFocus:aid(38127)
npcEnterFocus:register()

Outcome :
1679269532395.png
question is how'd I get her to engage in a convo instead of just saying it like that.
 
question is how'd I get her to engage in a convo instead of just saying it like that.
Lua:
local function onAppear(cid)
    local player = Player(cid)
    selfSay("Message Upon seeing a player") -- you can also use npcHandler to start a conversation directly in chat.
    npcHandler:setFocus(cid)
    npcHandler.topic[cid] = 1
    return true
end
npcHandler:setCallback(CALLBACK_CREATURE_APPEAR, onAppear)

npcHandler:setCallback(CALLBACK_MESSAGE_DEFAULT, creatureSayCallback)
-- Your creatureSayCallback here


--
npcHandler:addModule(FocusModule:new())
 
Lua:
local function onAppear(cid)
    local player = Player(cid)
    selfSay("Message Upon seeing a player") -- you can also use npcHandler to start a conversation directly in chat.
    npcHandler:setFocus(cid)
    npcHandler.topic[cid] = 1
    return true
end
npcHandler:setCallback(CALLBACK_CREATURE_APPEAR, onAppear)

npcHandler:setCallback(CALLBACK_MESSAGE_DEFAULT, creatureSayCallback)
-- Your creatureSayCallback here


--
npcHandler:addModule(FocusModule:new())
Yea this looks way better. Was just at this moment trying to understand your priest onThink script (the one where he cured and healed you if you had below 30% hp).
Only reason I went with @oserc 's way was cuz I find npc scripts so confusing for some reason... But now that Im looking at it, it doesnt seem at all as confusing as I imagined it being. Thanks m8!
Post automatically merged:

Edit, ofc thanks a lot to you too @oserc <3
 
Last edited:
Yea this looks way better. Was just at this moment trying to understand your priest onThink script (the one where he cured and healed you if you had below 30% hp).
Only reason I went with @oserc 's way was cuz I find npc scripts so confusing for some reason... But now that Im looking at it, it doesnt seem at all as confusing as I imagined it being. Thanks m8!
Post automatically merged:

Edit, ofc thanks a lot to you too @oserc <3
No problem, dude, good luck :)
 
Actually I ran into a bit of a problem. Well Seems like I spoke too soon, maybe Im still confused about Npc scripts. But this script only seems to be called when the server launches so the npc will only check if there is a player near it once + Im getting this error :
1679271746685.png
Im not sure if we're using the same tfs or whats up but I tried using this:
Lua:
local function onAppear(cid)
    local player = Player(cid)
    selfSay("Message Upon seeing a player") -- you can also use npcHandler to start a conversation directly in chat.
    npcHandler:setFocus(cid)
    npcHandler.topic[cid] = 1
    return true
end
npcHandler:setCallback(CALLBACK_CREATURE_APPEAR, onAppear)

npcHandler:setCallback(CALLBACK_MESSAGE_DEFAULT, creatureSayCallback)
-- Your creatureSayCallback here


--
npcHandler:addModule(FocusModule:new())
And it gave these errors:
1679271869730.png
I fixed those by chaning setFocus to addFocus but still same problem as earlier, it only checks on server launch. Maybe this is exactly what you intended with the script. In that case my question is how'd I make this execute everytime someone appears.
Again thanks a lot for all your responses guys! I dont know how to sound genuine by text but I do really appreciate it! <3


(In the first example I tried changing up the code to match what I thought looked more appropriate to my "standard" npc script)
Code below:
Lua:
local keywordHandler = KeywordHandler:new()
local npcHandler = NpcHandler:new(keywordHandler)
NpcSystem.parseParameters(npcHandler)
local talkState = {}
function onCreatureAppear(cid)
    npcHandler:onCreatureAppear(cid)
    npcHandler:addFocus(cid)
    selfSay("Shalom",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 creatureSayCallback(cid, type, msg)
    local talkUser = NPCHANDLER_CONVBEHAVIOR == CONVERSATION_DEFAULT and 0 or cid
    return true
end
npcHandler:setCallback(CALLBACK_MESSAGE_DEFAULT, creatureSayCallback)
 
Oh actually I get it, but now I only have the problem of the npc not seeming to care about z levels. It doesnt make sense for the npc to "see" you if youre above it. How'd I go about this issue?
 
Oh actually I get it, but now I only have the problem of the npc not seeming to care about z levels. It doesnt make sense for the npc to "see" you if youre above it. How'd I go about this issue?
On the onAppear callback you can add a condition to check if Npc():getPosition().z == player:getPosition().z
 
instead of looping through the tiles.. and trying to find the top creature
use Game.getSpectators(position[, multifloor = false[, onlyPlayer = false[, minRangeX = 0[, maxRangeX = 0[, minRangeY = 0[, maxRangeY = 0]]]]]])

Lua:
function onThink()
    local topLeft, botRight = Position(990, 990, 7), Position(1010, 1010, 7)
    local spectators = Game.getSpectators(centrePosition, false, true) -- defaults to range 11x11

    if #spectators > 0 then
        for _, player in pairs(spectators) do
            if player:getPosition():isInRange(topLeft, botRight) then -- here we check if they are inside the shop?
                -- do w/e you want to do
            end
        end
    end

    npcHandler:onThink()
end

Do it the way above, or fiddle with the minRange and maxRange. I can't stand using them myself.. but you do you. lol
 
instead of looping through the tiles.. and trying to find the top creature
use Game.getSpectators(position[, multifloor = false[, onlyPlayer = false[, minRangeX = 0[, maxRangeX = 0[, minRangeY = 0[, maxRangeY = 0]]]]]])

Lua:
function onThink()
    local topLeft, botRight = Position(990, 990, 7), Position(1010, 1010, 7)
    local spectators = Game.getSpectators(centrePosition, false, true) -- defaults to range 11x11

    if #spectators > 0 then
        for _, player in pairs(spectators) do
            if player:getPosition():isInRange(topLeft, botRight) then -- here we check if they are inside the shop?
                -- do w/e you want to do
            end
        end
    end

    npcHandler:onThink()
end

Do it the way above, or fiddle with the minRange and maxRange. I can't stand using them myself.. but you do you. lol
Hey man! Thanks a lot for your reply as usual! ^^ Are there any noob friendly documentation on tfs functions? (I do understand that I can look through the code and test etc), just asking incase I can save myself some struggle ^^ I did manage to find this : docs/tfs-documentation at master · otland/docs (https://github.com/otland/docs/tree/master/tfs-documentation)
But it seems like it was last updated 2 years ago so might be missing some new stuff + no npcs in that one. Yea sorry if this is common knowledge 😅
 
instead of looping through the tiles.. and trying to find the top creature
use Game.getSpectators(position[, multifloor = false[, onlyPlayer = false[, minRangeX = 0[, maxRangeX = 0[, minRangeY = 0[, maxRangeY = 0]]]]]])

Lua:
function onThink()
    local topLeft, botRight = Position(990, 990, 7), Position(1010, 1010, 7)
    local spectators = Game.getSpectators(centrePosition, false, true) -- defaults to range 11x11

    if #spectators > 0 then
        for _, player in pairs(spectators) do
            if player:getPosition():isInRange(topLeft, botRight) then -- here we check if they are inside the shop?
                -- do w/e you want to do
            end
        end
    end

    npcHandler:onThink()
end

Do it the way above, or fiddle with the minRange and maxRange. I can't stand using them myself.. but you do you. lol
Hey dude I know this is an old post and all but I just got back to trying to get this to work and I cant seem to get it.
This is what I have atm (just a copy of your code)
Lua:
function onThink()
    local centrePosition = Position(1057, 987, 6) -- set the centre position of your NPC's range
    local topLeft, botRight = Position(1054, 986, 6), Position(1059, 988, 6)
    local spectators = Game.getSpectators(centrePosition, false, true)

    if #spectators > 0 then
        for _, player in pairs(spectators) do
            if player:getPosition():isInRange(topLeft, botRight) then
                if not npcHandler:isFocused(player) then
                    selfSay("Hi there!".. " " .. player:getName(), player)
                    npcHandler:addFocus(player)
                end
            end
        end
    end

    npcHandler:onThink()
end
Problem with this is that it releases focus instantly after adding focus and giving this error :
Code:
onThink
NpcScriptInterface::luagetDistanceTo(). Thing not found
stack traceback:
        [C]: in function 'getDistanceTo'
        data/npc/lib/npcsystem/npchandler.lua:567: in function 'isInRange'
        data/npc/lib/npcsystem/npchandler.lua:502: in function 'onThink'
 
Hey dude I know this is an old post and all but I just got back to trying to get this to work and I cant seem to get it.
This is what I have atm (just a copy of your code)
Lua:
function onThink()
    local centrePosition = Position(1057, 987, 6) -- set the centre position of your NPC's range
    local topLeft, botRight = Position(1054, 986, 6), Position(1059, 988, 6)
    local spectators = Game.getSpectators(centrePosition, false, true)

    if #spectators > 0 then
        for _, player in pairs(spectators) do
            if player:getPosition():isInRange(topLeft, botRight) then
                if not npcHandler:isFocused(player) then
                    selfSay("Hi there!".. " " .. player:getName(), player)
                    npcHandler:addFocus(player)
                end
            end
        end
    end

    npcHandler:onThink()
end
Problem with this is that it releases focus instantly after adding focus and giving this error :
Code:
onThink
NpcScriptInterface::luagetDistanceTo(). Thing not found
stack traceback:
        [C]: in function 'getDistanceTo'
        data/npc/lib/npcsystem/npchandler.lua:567: in function 'isInRange'
        data/npc/lib/npcsystem/npchandler.lua:502: in function 'onThink'
afaik, this is because of the talk radius for that npc

Default is 3 or 4..
So you might need to change it for that npc, to accommodate the entire shop..
and then.. add an additional check in the onThink, to check if anyone is outside of the shop area? and releaseFocus
Kind of a weird problem. xP

or you could change the current function, to check if people are within the shop and also within 'talking range' of the npc
Which is probably a better solution.

Lua:
local centrePosition = Position(1057, 987, 6) -- set the centre position of your NPC's range
local topLeft, botRight = Position(1054, 986, 6), Position(1059, 988, 6)

function onThink()
    local spectators = Game.getSpectators(centrePosition, false, true)
    
    if #spectators > 0 then
        for _, player in pairs(spectators) do
            if not npcHandler:isFocused(player) then
                local playerPos = player:getPosition()
                if playerPos:isInRange(topLeft, botRight) then
                    if playerPos:getDistance(Creature(getNpcCid()):getPosition()) <= 3 then
                        selfSay("Hi there!".. " " .. player:getName(), player)
                        npcHandler:addFocus(player)
                    end
                end
            end
        end
    end
    
    npcHandler:onThink()
end
Post automatically merged:

--
Update

The problem was if not npcHandler:isFocused(player) then

The focus module was looking to receive a creatureId, not the creature data itself.

So changed the isFocused and addFocus to receive the spectator Id's instead, and the error went away.
 
Last edited:
this system of answering the player by distance seems to be interesting, but I think it needs to have a storage or count to repeat, imagine a player leaving and entering the screen, or several players arriving at the same time, or a war happening xD
 
this system of answering the player by distance seems to be interesting, but I think it needs to have a storage or count to repeat, imagine a player leaving and entering the screen, or several players arriving at the same time, or a war happening xD
Yea Im with you 100%, atm Im using it for a simple tutorial. So near spawn you will meet a npc that tells you about npcs and that you can talk to them etc, then after that first encounter I just give the player a storageValue so that they never enter that convo again. Same for a npc in a cave, she warns you about wholes and gives you a rope and shovel. Please share if you find any other you know actually good and reasonable use cases for this cuz I think its a good idea if correctly implemented!
 
Back
Top