• 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 Guard NPC - separate distance and melee attacks | error

AdiMit

c(;
Joined
May 2, 2016
Messages
70
Solutions
2
Reaction score
3
Hello :)

I'm currently using the [8.60] The Forgotten Server 0.3.6 (Crying Damson) V8 by Printer, from the thread: [8.60] The Forgotten Server 0.3.6 (Crying Damson) V8;

I was trying to redo the guard NPC(s) so that they would attack the PKers with melee attacks at the range of <=1; and with distance attacks at the range of >=2...
However, I get the following error after implementing the 'distance' part (works just fine without it).
By the way, I want the distance attacks to be carried out even if there is an obstacle on the way (for example another player who blocks the way), which seems to bug the NPC at the momoment...

The error:
Lua:
[03/08/2017 13:22:15] [Error - Npc interface]
[03/08/2017 13:22:15] data/npc/scripts/guard.lua:onThink
[03/08/2017 13:22:15] Description:
[03/08/2017 13:22:15] data/npc/scripts/guard.lua:108: attempt to call global 'sendDistanceEffect' (a nil value)
[03/08/2017 13:22:15] stack traceback:
[03/08/2017 13:22:15]     data/npc/scripts/guard.lua:108: in function <data/npc/scripts/guard.lua:70>

The script.lua:
Lua:
local target = 0
local prevTarget = 0
local maxChaseDistance = 20
local origPos = 0
local lastAttack = 0
local followTimeout = 10

local function isSkulled(cid)
    if(getCreatureSkullType(cid) >= SKULL_WHITE and isPlayerPzLocked(cid)) then
        return true
    end

    return false
end

local function goToOrigPos()
    target = 0
    lastAttack  = 0
    selfFollow(0)
    doTeleportThing(getNpcCid(), origPos)
end

local function updateTarget()
    if(not isPlayer(target)) then
        goToOrigPos()
    elseif(not isSkulled(target)) then
        selfSay("Now, behave in the future.")
        goToOrigPos()
    end

    if(target == 0) then
        local list = getSpectators(getNpcPos(), 9, 9, false)
        for i = 1, table.getn(list) do
            local _target = list[i]
            if(_target ~= 0) then
                if(isPlayer(_target) and isSkulled(_target)) then
                    if(not getTilePzInfo(getCreaturePosition(_target))) then
                        if(selfFollow(_target)) then
                            target = _target
                            if(target ~= prevTarget) then
                                selfSay("We do not tolerate people like you here!")
                            end

                            prevTarget = target
                            break
                        end
                    end
                end
            end
        end
    end
end

function onCreatureAppear(cid)
    if(cid == getNpcCid()) then
        origPos = getNpcPos()
    end
end

function onCreatureDisappear(cid)
    if(cid == target) then
        goToOrigPos()
    end
end

function onCreatureMove(creature, oldPos, newPos)
    --
end

function onThink()
    updateTarget()

    if(target == 0) then
        return
    end

    local playerPos = getCreaturePosition(target)
    local myPos = getNpcPos()

    if(myPos.z ~= playerPos.z) then
        goToOrigPos()
        return
    end

    if(math.abs(myPos.x - origPos.x) > maxChaseDistance or math.abs(myPos.y - origPos.y) > maxChaseDistance) then
        selfSay("I'll catch you next time.")
        goToOrigPos()
        return
    end

    if(lastAttack == 0) then
        lastAttack = os.clock()
    end

    if(os.clock() - lastAttack > followTimeout) then
        selfSay("You got me this time, but just wait.")
        goToOrigPos()
        return
    end

    if((math.abs(playerPos.x - myPos.x) <= 1) and (math.abs(playerPos.y - myPos.y) <= 1)) then
        doTargetCombatHealth(getNpcCid(), target, COMBAT_LIFEDRAIN, -220, -330, CONST_ME_BLOCKHIT)
        lastAttack = os.clock()
    end

    if((math.abs(playerPos.x - myPos.x) >= 2) and (math.abs(playerPos.y - myPos.y) >= 2)) then
        doTargetCombatHealth(getNpcCid(), target, COMBAT_PHYSICAL, -110, -220, CONST_ME_HITAREA)
        sendDistanceEffect(target, CONST_ANI_WHIRLWINDSWORD)
        lastAttack = os.clock()
    end
end

The NPC.xml:
Lua:
<?xml version="1.0" encoding="UTF-8"?>
<npc name="Guardsman" script="guard.lua" walkinterval="0" floorchange="0" speed="1100">
    <health now="100000" max="100000"/>
    <look type="131" head="95" body="132" legs="96" feet="116" addons="3"/>

  <interaction range="3" idletime="60">

    <interact keywords="hi" focus="1">
      <keywords>hello</keywords>

      <response text="Nothing to see here, move along.">
        <action name="idle" value="1"/>
      </response>
    </interact>

    <interact keywords="bye" focus="0">
      <keywords>farewell</keywords>

      <response text="Good bye."/>
    </interact>
  </interaction>

</npc>

Do you have any ideas how to resolve the issue?

Thanks in advance! ;)
Best regards.
 
Solution
Now I get this error:
Lua:
[03/08/2017 14:40:24] [Error - LuaScriptInterface::loadFile] data/npc/scripts/guard.lua:108: unexpected symbol near ','
[03/08/2017 14:40:24] [Warning - NpcScript::NpcScript] Cannot load script: data/npc/scripts/guard.lua
[03/08/2017 14:40:24] data/npc/scripts/guard.lua:108: unexpected symbol near ','

By the way, where in this script do I specify the distance effect?

Best regards.

The function is:
Lua:
doSendDistanceShoot
First variable is fromPosition = location the effect is sent from.
Second variable is toPosition = location the effect should go to.
Third variable is the effect, in your case CONST_ANI_WHIRLWINDSWORD

I guess you can try this;
Lua:
doSendDistanceShoot(myPos, playerPos...
Code:
attempt to call global 'sendDistanceEffect' (a nil value)
call global -> this means it's trying to call a function or local
nil -> means it doesn't exist.

So basically, the function 'sendDistanceEffect' does not exist.
You either spelt the function incorrectly, or it truly does not exist.

The first thing I thought was "doSendDistanceEffect".. as all functions basically use do in front of them..
But after checking luascript.cpp, I realised the function is named a bit differently.

---

tl:dr -> Use the correct function.
//doSendDistanceShoot(fromPos, toPos, type[, player])
 
Code:
attempt to call global 'sendDistanceEffect' (a nil value)
call global -> this means it's trying to call a function or local
nil -> means it doesn't exist.

So basically, the function 'sendDistanceEffect' does not exist.
You either spelt the function incorrectly, or it truly does not exist.

The first thing I thought was "doSendDistanceEffect".. as all functions basically use do in front of them..
But after checking luascript.cpp, I realised the function is named a bit differently.

---

tl:dr -> Use the correct function.
//doSendDistanceShoot(fromPos, toPos, type[, player])

Now I get this error:
Lua:
[03/08/2017 14:40:24] [Error - LuaScriptInterface::loadFile] data/npc/scripts/guard.lua:108: unexpected symbol near ','
[03/08/2017 14:40:24] [Warning - NpcScript::NpcScript] Cannot load script: data/npc/scripts/guard.lua
[03/08/2017 14:40:24] data/npc/scripts/guard.lua:108: unexpected symbol near ','

By the way, where in this script do I specify the distance effect?

Best regards.
 
Now I get this error:
Lua:
[03/08/2017 14:40:24] [Error - LuaScriptInterface::loadFile] data/npc/scripts/guard.lua:108: unexpected symbol near ','
[03/08/2017 14:40:24] [Warning - NpcScript::NpcScript] Cannot load script: data/npc/scripts/guard.lua
[03/08/2017 14:40:24] data/npc/scripts/guard.lua:108: unexpected symbol near ','

By the way, where in this script do I specify the distance effect?

Best regards.

The function is:
Lua:
doSendDistanceShoot
First variable is fromPosition = location the effect is sent from.
Second variable is toPosition = location the effect should go to.
Third variable is the effect, in your case CONST_ANI_WHIRLWINDSWORD

I guess you can try this;
Lua:
doSendDistanceShoot(myPos, playerPos, CONST_ANI_WHIRLWINDSWORD)

Ref; forgottenserver036pl1/luascript.cpp at master · peonso/forgottenserver036pl1 · GitHub
 
Last edited:
Solution
The function is:
Lua:
doSendDistanceShoot
First variable is fromPosition = location the effect is sent from.
Second variable is toPosition = location the effect should go to.
Third variable is the effect, in your case CONST_ANI_WHIRLWINDSWORD

I guess you can try this;
Lua:
doSendDistanceShoot(origPos, target, CONST_ANI_WHIRLWINDSWORD)

Ref; forgottenserver036pl1/luascript.cpp at master · peonso/forgottenserver036pl1 · GitHub

Now, when the path is blocked by another player and the NPC is supposed to attack the PKer, I get this:
Lua:
[03/08/2017 14:51:34] [Error - Npc interface]
[03/08/2017 14:51:34] data/npc/scripts/guard.lua:onThink
[03/08/2017 14:51:34] Description:
[03/08/2017 14:51:34] attempt to index a number value
[03/08/2017 14:51:34] stack traceback:
[03/08/2017 14:51:34]     [C]: in function 'doSendDistanceShoot'
[03/08/2017 14:51:34]     data/npc/scripts/guard.lua:108: in function <data/npc/scripts/guard.lua:70>

The whole script looks as follows:
Lua:
local target = 0
local prevTarget = 0
local maxChaseDistance = 20
local origPos = 0
local lastAttack = 0
local followTimeout = 10

local function isSkulled(cid)
    if(getCreatureSkullType(cid) >= SKULL_WHITE and isPlayerPzLocked(cid)) then
        return true
    end

    return false
end

local function goToOrigPos()
    target = 0
    lastAttack  = 0
    selfFollow(0)
    doTeleportThing(getNpcCid(), origPos)
end

local function updateTarget()
    if(not isPlayer(target)) then
        goToOrigPos()
    elseif(not isSkulled(target)) then
        selfSay("Now, behave in the future.")
        goToOrigPos()
    end

    if(target == 0) then
        local list = getSpectators(getNpcPos(), 9, 9, false)
        for i = 1, table.getn(list) do
            local _target = list[i]
            if(_target ~= 0) then
                if(isPlayer(_target) and isSkulled(_target)) then
                    if(not getTilePzInfo(getCreaturePosition(_target))) then
                        if(selfFollow(_target)) then
                            target = _target
                            if(target ~= prevTarget) then
                                selfSay("We do not tolerate people like you here!")
                            end

                            prevTarget = target
                            break
                        end
                    end
                end
            end
        end
    end
end

function onCreatureAppear(cid)
    if(cid == getNpcCid()) then
        origPos = getNpcPos()
    end
end

function onCreatureDisappear(cid)
    if(cid == target) then
        goToOrigPos()
    end
end

function onCreatureMove(creature, oldPos, newPos)
    --
end

function onThink()
    updateTarget()

    if(target == 0) then
        return
    end

    local playerPos = getCreaturePosition(target)
    local myPos = getNpcPos()

    if(myPos.z ~= playerPos.z) then
        goToOrigPos()
        return
    end

    if(math.abs(myPos.x - origPos.x) > maxChaseDistance or math.abs(myPos.y - origPos.y) > maxChaseDistance) then
        selfSay("I'll catch you next time.")
        goToOrigPos()
        return
    end

    if(lastAttack == 0) then
        lastAttack = os.clock()
    end

    if(os.clock() - lastAttack > followTimeout) then
        selfSay("You got me this time, but just wait.")
        goToOrigPos()
        return
    end

    if((math.abs(playerPos.x - myPos.x) <= 1) and (math.abs(playerPos.y - myPos.y) <= 1)) then
        doTargetCombatHealth(getNpcCid(), target, COMBAT_LIFEDRAIN, -220, -330, CONST_ME_BLOCKHIT)
        lastAttack = os.clock()
    end

    if((math.abs(playerPos.x - myPos.x) >= 2) and (math.abs(playerPos.y - myPos.y) >= 2)) then
        doTargetCombatHealth(getNpcCid(), target, COMBAT_PHYSICAL, -110, -220, CONST_ME_HITAREA)
        doSendDistanceShoot(getNpcPos(), target, CONST_ANI_WHIRLWINDSWORD)
        lastAttack = os.clock()
    end
end
 
Now, when the path is blocked by another player and the NPC is supposed to attack the PKer, I get this:
Lua:
[03/08/2017 14:51:34] [Error - Npc interface]
[03/08/2017 14:51:34] data/npc/scripts/guard.lua:onThink
[03/08/2017 14:51:34] Description:
[03/08/2017 14:51:34] attempt to index a number value
[03/08/2017 14:51:34] stack traceback:
[03/08/2017 14:51:34]     [C]: in function 'doSendDistanceShoot'
[03/08/2017 14:51:34]     data/npc/scripts/guard.lua:108: in function <data/npc/scripts/guard.lua:70>

The whole script looks as follows:
Lua:
local target = 0
local prevTarget = 0
local maxChaseDistance = 20
local origPos = 0
local lastAttack = 0
local followTimeout = 10

local function isSkulled(cid)
    if(getCreatureSkullType(cid) >= SKULL_WHITE and isPlayerPzLocked(cid)) then
        return true
    end

    return false
end

local function goToOrigPos()
    target = 0
    lastAttack  = 0
    selfFollow(0)
    doTeleportThing(getNpcCid(), origPos)
end

local function updateTarget()
    if(not isPlayer(target)) then
        goToOrigPos()
    elseif(not isSkulled(target)) then
        selfSay("Now, behave in the future.")
        goToOrigPos()
    end

    if(target == 0) then
        local list = getSpectators(getNpcPos(), 9, 9, false)
        for i = 1, table.getn(list) do
            local _target = list[i]
            if(_target ~= 0) then
                if(isPlayer(_target) and isSkulled(_target)) then
                    if(not getTilePzInfo(getCreaturePosition(_target))) then
                        if(selfFollow(_target)) then
                            target = _target
                            if(target ~= prevTarget) then
                                selfSay("We do not tolerate people like you here!")
                            end

                            prevTarget = target
                            break
                        end
                    end
                end
            end
        end
    end
end

function onCreatureAppear(cid)
    if(cid == getNpcCid()) then
        origPos = getNpcPos()
    end
end

function onCreatureDisappear(cid)
    if(cid == target) then
        goToOrigPos()
    end
end

function onCreatureMove(creature, oldPos, newPos)
    --
end

function onThink()
    updateTarget()

    if(target == 0) then
        return
    end

    local playerPos = getCreaturePosition(target)
    local myPos = getNpcPos()

    if(myPos.z ~= playerPos.z) then
        goToOrigPos()
        return
    end

    if(math.abs(myPos.x - origPos.x) > maxChaseDistance or math.abs(myPos.y - origPos.y) > maxChaseDistance) then
        selfSay("I'll catch you next time.")
        goToOrigPos()
        return
    end

    if(lastAttack == 0) then
        lastAttack = os.clock()
    end

    if(os.clock() - lastAttack > followTimeout) then
        selfSay("You got me this time, but just wait.")
        goToOrigPos()
        return
    end

    if((math.abs(playerPos.x - myPos.x) <= 1) and (math.abs(playerPos.y - myPos.y) <= 1)) then
        doTargetCombatHealth(getNpcCid(), target, COMBAT_LIFEDRAIN, -220, -330, CONST_ME_BLOCKHIT)
        lastAttack = os.clock()
    end

    if((math.abs(playerPos.x - myPos.x) >= 2) and (math.abs(playerPos.y - myPos.y) >= 2)) then
        doTargetCombatHealth(getNpcCid(), target, COMBAT_PHYSICAL, -110, -220, CONST_ME_HITAREA)
        doSendDistanceShoot(getNpcPos(), target, CONST_ANI_WHIRLWINDSWORD)
        lastAttack = os.clock()
    end
end

Use playerPos insted of target
 
Use playerPos insted of target

Lua:
    if((math.abs(playerPos.x - myPos.x) >= 2) and (math.abs(playerPos.y - myPos.y) >= 2)) then
        doTargetCombatHealth(getNpcCid(), target, COMBAT_LIFEDRAIN, -110, -220, CONST_ME_BLOCKHIT)
        doSendDistanceShoot(getNpcPos(), playerPos, CONST_ANI_WHIRLWINDSWORD)
        lastAttack = os.clock()
    end
end

Works! :D

Thank you kindly! :)
 
Lua:
    if((math.abs(playerPos.x - myPos.x) >= 2) and (math.abs(playerPos.y - myPos.y) >= 2)) then
        doTargetCombatHealth(getNpcCid(), target, COMBAT_LIFEDRAIN, -110, -220, CONST_ME_BLOCKHIT)
        doSendDistanceShoot(getNpcPos(), playerPos, CONST_ANI_WHIRLWINDSWORD)
        lastAttack = os.clock()
    end
end

Works! :D

Thank you kindly! :)

A tip use
Lua:
myPos
insted, since
Lua:
getNpcPos()
has already been called on line 77
 
Back
Top