• 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+ Creatureevent; Find killed creature in an area.

Klank

Althea ¤ A New World Developer
Joined
Feb 21, 2008
Messages
1,077
Reaction score
631
Location
Norway
Hello!
Im struggling on getting this code to work.. So, the start of this function is 4x different creatures(not random) summoned when performing an action. What i want this script to do, is to search an area defined in the code, to confirm that all 4 creatures are killed. That is, 1 ghoul, 1 ghost , 1 demon skeleton and 1 skeleton has to be killed to create a teleport. Can't get my head around this.

Lua:
local area = {
    centerTilePos = Position(558, 744, 7),
    tilesToLeft = 5,
    tilesToRight = 5,
    tilesToTop = 2,
    tilesToBottom = 2,
    teleportPos =  Position(554,745,7)
}
local monsterNames = {"ghoul","ghost","demon skeleton","skeleton",
}
function onKill(cid, target, lastHit)
    local targetName = string.lower(getCreatureName(target))

    if isMonster(target) and table.contains(monsterNames, targetName)  then -- checks if killed thing is monster and monster with right name
        local spectators = Game.getSpectators(area.centerTilePos, false, false, 5,5,2,2) -- find every creature in room

        for key, creature in pairs(spectators) do
            if isMonster(creature) then -- finish script
                return true

            else
                doCreateTeleport(1387, getThingPos(target), area.teleportPos)-- creating teleport at position
            end
        end
    end


    return true
end
 
Lua:
local config = {
    center = Position(558, 744, 7),
    rangeX = 5,
    rangeY = 2,
    teleport = {
        id = 1387,
        destination = Position(554,745,7),
    }
    monsters = {"ghoul","ghost","demon skeleton","skeleton",},
}

local function monstersAlive(center, rangeX, rangeY, monsters)
    local area = Game.getSpectators(center, false, false, rangeX, rangeX, rangeY, rangeY)
    for i, k in ipairs(area) do
        if isMonster(k) and table.find(monsters, getCreatureName(k)) then
            return true
        end
    end
    return false
end

function onKill(cid, target, lastHit)
    if monstersAlive(config.center, config.rangeX, config.rangeY, config.monsters) then
        return false
    end

    doCreateTeleport(config.teleport.id, getThingPos(target), config.teleport.destination)
    return true
end
btw. I don't know why you using compact.lua for reverse compatibility while using TFS 1.X+ (I guess you using one from newest TFS due to recognizing "Position" notation).
Try to get used to object oriented coding instead of using old functions from compact.lua. Peace.
 
Last edited:
you'd always want to return true in the onKill method, or the monster won't die.
Probably want to check if the monsters are summons as well, in case a player has some out, for w/e reason.

Might have to delay the check in area.. because the monster being killed might still be 'alive' when the check is being performed.

--
I'd probably change this to be a globalstorage and onDeath for the monsters.
Instead of counting remaining monsters.. you'd just increase the globalstorage by 1..
and when you hit threshold, spawn portal + reset global storage at some point.
 
Lua:
local config = {
    center = Position(558, 744, 7),
    rangeX = 5,
    rangeY = 2,
    teleport = {
        id = 1387,
        destination = Position(554,745,7),
    }
    monsters = {"ghoul","ghost","demon skeleton","skeleton",},
}

local function monstersAlive(center, rangeX, rangeY, monsters)
    local area = Game.getSpectators(center, false, false, rangeX, rangeX, rangeY, rangeY)
    for i, k in ipairs(area) do
        if isMonster(k) and table.find(monsters, getCreatureName(k)) then
            return true
        end
    end
    return false
end

function onKill(cid, target, lastHit)
    if monstersAlive(config.center, config.rangeX, config.rangeY, config.monsters) then
        return false
    end

    doCreateTeleport(config.teleport.id, getThingPos(target), config.teleport.destination)
    return true
end
btw. I don't know why you using compact.lua for reverse compatibility while using TFS 1.X+ (I guess you using one from newest TFS due to recognizing "Position" notation).
Try to get used to object oriented coding instead of using old functions from compact.lua. Peace.

Thanks for the reply.
I am new to scripting, and trying to learn. Im using TFS 1.3 and well, i just started the scripting from there.
However, ur code does not work. I did some minor changes due to errors;
Lua:
local config = {
    center = Position(558, 744, 7),
    rangeX = 5,
    rangeY = 2,
    teleportPos = Position(554,745,7),
    monsters = {"ghoul","ghost","demon skeleton","skeleton",},
}

function monstersAlive(center, rangeX, rangeY, monsters)
    local area = Game.getSpectators(config.center, false, false, config.rangeX, config.rangeX, config.rangeY, config.rangeY)
    for i, k in ipairs(area) do
        if isMonster(k) and table.contains(monsters, getCreatureName(k)) then
            return true
        end
    end
    return false
end

function onKill(cid, target, lastHit)
    if monstersAlive(config.center, config.rangeX, config.rangeY, config.monsters) then
        return false
    end

    doCreateTeleport(1387, getThingPos(target), area.teleportPos)

    return true
end

The "table.find" did not work, changed it to table.contains. Also some correct calling of table was fixed. However, i'm getting this; Im guessing it has something to do with the local function monstersAlive?
1674762583532.png
 
Thanks for the reply.
I am new to scripting, and trying to learn. Im using TFS 1.3 and well, i just started there scripting from there.
However, ur code does not work. I did some minor changes due to errors;
Lua:
local config = {
    center = Position(558, 744, 7),
    rangeX = 5,
    rangeY = 2,
    teleportPos = Position(554,745,7),
    monsters = {"ghoul","ghost","demon skeleton","skeleton",},
}

function monstersAlive(center, rangeX, rangeY, monsters)
    local area = Game.getSpectators(config.center, false, false, config.rangeX, config.rangeX, config.rangeY, config.rangeY)
    for i, k in ipairs(area) do
        if isMonster(k) and table.contains(monsters, getCreatureName(k)) then
            return true
        end
    end
    return false
end

function onKill(cid, target, lastHit)
    if monstersAlive(config.center, config.rangeX, config.rangeY, config.monsters) then
        return false
    end

    doCreateTeleport(1387, getThingPos(target), area.teleportPos)

    return true
end

The "table.find" did not work, changed it to table.contains. Also some correct calling of table was fixed. However, i'm getting this; Im guessing it has something to do with the local function monstersAlive?
View attachment 73010
table name changed from area to config.
so edit for config.teleportPos
 
You'll also need to change monsters to config.monsters on line 12
You don't need because it's reading passed "config.monsters" in function parameter in usage in main function. Edited main post.

you'd always want to return true in the onKill method, or the monster won't die.
Probably want to check if the monsters are summons as well, in case a player has some out, for w/e reason.

Might have to delay the check in area.. because the monster being killed might still be 'alive' when the check is being performed.

--
I'd probably change this to be a globalstorage and onDeath for the monsters.
Instead of counting remaining monsters.. you'd just increase the globalstorage by 1..
and when you hit threshold, spawn portal + reset global storage at some point.

Another option is to start addEvent in loop when entering/executing script/whatever in area to check if monsters are alive, there are many options to handle that.
onKill is not a good way for this idea, but he wanted it like that :rolleyes:
 
you'd always want to return true in the onKill method, or the monster won't die.
Probably want to check if the monsters are summons as well, in case a player has some out, for w/e reason.

Might have to delay the check in area.. because the monster being killed might still be 'alive' when the check is being performed.

--
I'd probably change this to be a globalstorage and onDeath for the monsters.
Instead of counting remaining monsters.. you'd just increase the globalstorage by 1..
and when you hit threshold, spawn portal + reset global storage at some point.
Note taken, thanks.
Thats a very good point, ill have to check summons aswell.
table name changed from area to config.
so edit for config.teleportPos
Lol, thanks..
You don't need because it's reading passed "config.monsters" in function parameter in usage in main function. Edited main post.



Another option is to start addEvent in loop when entering/executing script/whatever in area to check if monsters are alive, there are many options to handle that.
onKill is not a good way for this idea, but he wanted it like that :rolleyes:

Script now goes through, but is spawning teleport upon first creature killed. Just like my own script xd
 
You don't need because it's reading passed "config.monsters" in function parameter in usage in main function. Edited main post.



Another option is to start addEvent in loop when entering/executing script/whatever in area to check if monsters are alive, there are many options to handle that.
onKill is not a good way for this idea, but he wanted it like that :rolleyes:

Sorry yes my bad, didn't see the param :p
 
You don't need because it's reading passed "config.monsters" in function parameter in usage in main function. Edited main post.



Another option is to start addEvent in loop when entering/executing script/whatever in area to check if monsters are alive, there are many options to handle that.
onKill is not a good way for this idea, but he wanted it like that :rolleyes:

It's not that i want that, but im trying to understand functions etc, and i have not worked with onDeath yet. So i guess that would change the whole structure of the code again. Just to make u understand, this is my first creaturescript ever :p
 
If the creatures are being summoned, just register an event to them when they are spawned, and just run an onDeath script. No need to call getSpectators for this. Each onDeath decrements an integer count stored in memory as a global, and then execute whatever function when its 0 (all creatures killed).

Would be better if you used revscript, as you could store all of this in one file.

However, if it's just your first script, keep with the one you've got. But keep learning :)
 
If the creatures are being summoned, just register an event to them when they are spawned, and just run an onDeath script. No need to call getSpectators for this. Each onDeath decrements an integer count stored in memory as a global, and then execute whatever function when its 0 (all creatures killed).

Would be better if you used revscript, as you could store all of this in one file.

However, if it's just your first script, keep with the one you've got. But keep learning :)

To be honest, i dont know what RevScripts are yet. Much to learn.
I would be fine by changing it, but spent so much time on this, that without proper follow-up im guessing i would use just as much time on the onDeath function xd.
 
To be honest, i dont know what RevScripts are yet. Much to learn.
I would be fine by changing it, but spent so much time on this, that without proper follow-up im guessing i would use just as much time on the onDeath function xd.
Can you post the current script that is not working?
 
getSpectators already passes the class object through so you can just do this:
Lua:
function monstersAlive(center, rangeX, rangeY, monsters)
    local spectators = Game.getSpectators(config.center, false, false, config.rangeX, config.rangeX, config.rangeY, config.rangeY)
    for _, spectator in ipairs(spectators) do
        if spectator:isMonster() and table.contains(monsters, spectator:getName()) then
            return true
        end
    end
    return false
end
 
Can you post the current script that is not working?
This is the one that is "working", but create the teleports on first (1/4) kills
Lua:
local config = {
    center = Position(558, 744, 7),
    rangeX = 5,
    rangeY = 2,
    teleportPos = Position(554,745,7),
    monsters = {"ghoul","ghost","demon skeleton","skeleton",},
}

local function monstersAlive(center, rangeX, rangeY, monsters)
    local area = Game.getSpectators(config.center, false, false, config.rangeX, config.rangeX, config.rangeY, config.rangeY)
    for i, k in ipairs(area) do
        if isMonster(k) and table.contains(monsters, getCreatureName(k)) then
            return true
        end
    end
    return false
end


function onKill(cid, target, lastHit)
    if monstersAlive(config.center, config.rangeX, config.rangeY, config.monsters) then
        return false
    end
     doCreateTeleport(1387, Position(556,745,7), Position(558,744,7))

    return true
end

getSpectators already passes the class object through so you can just do this:
Lua:
function monstersAlive(center, rangeX, rangeY, monsters)
    local spectators = Game.getSpectators(config.center, false, false, config.rangeX, config.rangeX, config.rangeY, config.rangeY)
    for _, spectator in ipairs(spectators) do
        if spectator:isMonster() and table.contains(monsters, spectator:getName()) then
            return true
        end
    end
    return false
end
(tested this seperatly, not in code above)
spectator:isMonster() generates error:
Lua Script Error: [CreatureScript Interface]
data/creaturescripts/scripts/custom/SaveFeldenRoom1.lua:eek:nKill
data/creaturescripts/scripts/custom/SaveFeldenRoom1.lua:14: attempt to call method 'isMonster' (a nil value)
stack traceback:
[C]: in function 'isMonster'
data/creaturescripts/scripts/custom/SaveFeldenRoom1.lua:14: in function 'monstersAlive'
data/creaturescripts/scripts/custom/SaveFeldenRoom1.lua:23: in function <data/creaturescripts/scripts/custom/SaveFeldenRoom1.lua:22>
 
Change onKill to this and check what is going on
Lua:
function onKill(cid, target, lastHit)
    if not monstersAlive(config.center, config.rangeX, config.rangeY, config.monsters) then
        doCreateTeleport(1387, Position(556,745,7), Position(558,744,7))
        return true
    end

    return true
end
 
Hello!
Im struggling on getting this code to work.. So, the start of this function is 4x different creatures(not random) summoned when performing an action. What i want this script to do, is to search an area defined in the code, to confirm that all 4 creatures are killed. That is, 1 ghoul, 1 ghost , 1 demon skeleton and 1 skeleton has to be killed to create a teleport. Can't get my head around this.

Lua:
local area = {
    centerTilePos = Position(558, 744, 7),
    tilesToLeft = 5,
    tilesToRight = 5,
    tilesToTop = 2,
    tilesToBottom = 2,
    teleportPos =  Position(554,745,7)
}
local monsterNames = {"ghoul","ghost","demon skeleton","skeleton",
}
function onKill(cid, target, lastHit)
    local targetName = string.lower(getCreatureName(target))

    if isMonster(target) and table.contains(monsterNames, targetName)  then -- checks if killed thing is monster and monster with right name
        local spectators = Game.getSpectators(area.centerTilePos, false, false, 5,5,2,2) -- find every creature in room

        for key, creature in pairs(spectators) do
            if isMonster(creature) then -- finish script
                return true

            else
                doCreateTeleport(1387, getThingPos(target), area.teleportPos)-- creating teleport at position
            end
        end
    end


    return true
end
Lua:
local config = {
    topLeftCorner = {x = 994, y = 1007, z = 7},
    bottomRightCorner = {x = 997, y = 1009, z = 7},
    teleportPos =  {x = 996, y = 1010, z = 7}
}
local monsterNames = {"ghoul","ghost","demon skeleton","skeleton"}
local killedCounter = {ghoul = 0, ghost = 0, ["demon skeleton"] = 0, skeleton = 0}

local topLeft = Position(config.topLeftCorner.x, config.topLeftCorner.y, config.topLeftCorner.z)
local bottomRight = Position(config.bottomRightCorner.x, config.bottomRightCorner.y, config.bottomRightCorner.z)
local teleport = Position(config.teleportPos.x, config.teleportPos.y, config.teleportPos.z)

function onKill(cid, target, lastHit)
    local targetName = string.lower(getCreatureName(target))
    local targetPos = getThingPos(target)
    if isMonster(target) and table.contains(monsterNames, targetName) and targetPos:isInRange(topLeft, bottomRight) then
        killedCounter[targetName] = killedCounter[targetName] + 1
            if killedCounter.ghoul > 0 and killedCounter.ghost > 0 and killedCounter["demon skeleton"] > 0 and killedCounter.skeleton > 0 then
            doCreateTeleport(1387, teleport, getThingPos(cid))
        end
    end
    return true
end
 
This is script that you want. You have to check if the monster you are killing is the last monster in the area.
onKill event triggers before creature is dead, that is why you never had your area cleared
Also getCreatureName function returns creature name with capital letters, so monsters in your config also needs capital letters

Lua:
local config = {
    center = Position(558, 744, 7),
    rangeX = 5,
    rangeY = 2,
    teleportPos = Position(554,745,7),
    monsters = {"Ghoul","Ghost","Demon Skeleton","Skeleton",},
}

local function monstersAlive(center, rangeX, rangeY, monsters, currentMonsterCid)
    local currentMonster = Monster(currentMonsterCid)
    local area = Game.getSpectators(config.center, false, false, config.rangeX, config.rangeX, config.rangeY, config.rangeY)
    for i, k in ipairs(area) do
        if isMonster(k) and table.contains(monsters, getCreatureName(k)) and k ~= currentMonster  then
            return true
        end
    end
    return false
end


function onKill(cid, target, lastHit)
    if not monstersAlive(config.center, config.rangeX, config.rangeY, config.monsters, target) then
        doCreateTeleport(1387, Position(556,745,7), Position(558,744,7))
        return true
    end


    return true
end
 
Okey guys, small update. Got it to work with help from "Trollheim", so all credits to Trollheim. However, i duplicated and changed the creatures in config lua for my second script.
Also, moved from TFS 1.3 to TFS 1.4.2 (not relevant maybe)
Problem is: When executing the first script, i set the storage value in the second script, and if i add a similar third script, the storage value in that is set on first script as well. Events are registered on login and in creatureevent.xml.
I appreciate the help I've already got earlier, but seems I'm in need of more :<

Question: When using same name of functions in different scripts, does it matter if its local function or not?

First script:
Lua:
local config = {
    center = Position(558, 744, 7),
    rangeX = 5,
    rangeY = 2,
    effectY = 1,
    effectX = 4,
    --teleportPos = Position(554,745,7),
    monsters = {"Ghoul","Ghost","Demon Skeleton","Skeleton",},
}

local function monstersAlive(center, rangeX, rangeY, monsters, currentMonsterCid)
    local currentMonster = Monster(currentMonsterCid)
    local area = Game.getSpectators(config.center, false, false, config.rangeX, config.rangeX, config.rangeY, config.rangeY)
    for i, k in ipairs(area) do
        if isMonster(k) and table.contains(config.monsters, getCreatureName(k)) and k ~= currentMonster and not isSummon(k) then
            return true
        end
    end
    return false
end

local function spawnEffectOnPos(position)
    doSendMagicEffect(position, CONST_ME_HITBYFIRE)
end

local function fireAnimation()
    local howManyEffects = 25
    for i = 1, howManyEffects do
        local effectPos = Position(
            math.random(config.center.x - config.effectX, config.center.x + config.effectX),
            math.random(config.center.y - config.effectY, config.center.y + config.effectY),
            config.center.z
        )
        addEvent(spawnEffectOnPos, 25 * i, effectPos)
    end

end
function onKill(cid, target, lastHit)
    if isSummon(target) then
        return true
    end
    if not monstersAlive(config.center, config.rangeX, config.rangeY, config.monsters, target) then
        local area = Game.getSpectators(config.center, false, false, config.rangeX, config.rangeX, config.rangeY, config.rangeY)
        cid:setStorageValue(Storage.SaveFrelden, 3)
        fireAnimation()
        for i, k in ipairs(area) do
            if isPlayer(k) then
                doSendMagicEffect(getCreaturePos(k), CONST_ME_HOLYAREA)
            end
        end
        return true
    end

    return true
end

Second script ( Second Room)

Lua:
local config = {
    center = Position(558, 750, 6),
    rangeX = 5,
    rangeY = 2,
    effectY = 1,
    effectX = 4,
    monster = {"Crypt Shambler","Ghoul","Bonelord","Mummy","Skeleton Warrior",},
}

local function monstersAlive(center, rangeX, rangeY, monster, currentMonsterCid)
    local currentMonster = Monster(currentMonsterCid)
    local area = Game.getSpectators(config.center, false, false, config.rangeX, config.rangeX, config.rangeY, config.rangeY)
    for i, k in ipairs(area) do
        if isMonster(k) and table.contains(config.monster, getCreatureName(k)) and k ~= currentMonster and not isSummon(k) then
            return true
        end
    end
    return false
end

local function spawnEffectOnPos(position)
    doSendMagicEffect(position, CONST_ME_HITBYFIRE)
end

local function fireAnimation()
    local howManyEffects = 25
    for i = 1, howManyEffects do
        local effectPos = Position(
            math.random(config.center.x - config.effectX, config.center.x + config.effectX),
            math.random(config.center.y - config.effectY, config.center.y + config.effectY),
            config.center.z
        )
        addEvent(spawnEffectOnPos, 25 * i, effectPos)
    end

end

function onKill(cid, target, lastHit)
    if isSummon(target) then
        return true
    end
    if not monstersAlive(config.center, config.rangeX, config.rangeY, config.monsters, target) then
        local area = Game.getSpectators(config.center, false, false, config.rangeX, config.rangeX, config.rangeY, config.rangeY)
        cid:setStorageValue(Storage.SaveFrelden, 4)
        fireAnimation()
        for i, k in ipairs(area) do
            if isPlayer(k) then
                doSendMagicEffect(getCreaturePos(k), CONST_ME_HOLYAREA)
            end
        end
        return true
    end

    return true
end
 
Back
Top