• 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 0.4 - Count amount of specific monster in 2d area

Game.getSpectators

Will find any alive creatures in the configured area around specified position.

The map spawn.xml file should contain information about spawns:

Which you could do some math on to figure out nearly creatures of a given position.

Edit:
Ohh, 0.4. :/ Sorry, didnt knew we were back in 2009. Just look for the 0.4 equivalent of getspectators, see if it grabs creatures as well, or if you can configure it to do so.
 
Game.getSpectators

Will find any alive creatures in the configured area around specified position.

The map spawn.xml file should contain information about spawns:

Which you could do some math on to figure out nearly creatures of a given position.

Edit:
Ohh, 0.4. :/ Sorry, didnt knew we were back in 2009. Just look for the 0.4 equivalent of getspectators, see if it grabs creatures as well, or if you can configure it to do so.

managed to write the function for it but not sure if its efficient enough, the area to be scanned is 5x5

Lua:
function countMonster(name, startPos, endPos)
    local counter = 0
    for i = startPos.y, endPos.y, 1 do
        for j = startPos.x, endPos.x, 1 do
            local topMonster = getTopCreature({x = j, y = i, z = 7}).uid
            if(isMonster(topMonster) and getCreatureName(topMonster) == name) then
                counter = counter + 1
            end
        end
    end

    return counter
end
 
@Snavy Nice, but you forgot to loop through z. You might wanna use that function for something else than groun floor (z = 7).

Had some fun and made a more "generic" multi-purpose getCreatures function based on your code:
Lua:
function getCreatures(fromPos, toPos)
    -- No matter what corner from and to is, we want to make 
    -- life easier by calculating north-west and south-east (before we start looping)
    local zone = {
        northWest = {
            x = (fromPos.x < toPos.x and fromPos.x or toPos.x),
            y = (fromPos.y < toPos.y and fromPos.y or toPos.y),
            z = (fromPos.z < toPos.z and fromPos.z or toPos.z)
        },
        southEast = {
            x = (toPos.x > fromPos.x and toPos.x or fromPos.x),
            y = (toPos.y > fromPos.y and toPos.y or fromPos.y),
            z = (toPos.z > fromPos.z and toPos.z or fromPos.z)
        }
    }
    -- data to be returned once populated
    local data = {
        count = {
            creatures = 0,
            monsters = 0,
            players = 0,
            npcs = 0
        },
        keys = {
            monsters = {},
            players = {},
            npcs = {}
        },
        creatures = {}
    }
    -- scan area and populate the data table above
    local i = 1
    for pz = zone.northWest.z, zone.southEast.z, 1 do
        for py = zone.northWest.y, zone.southEast.y, 1 do
            for px = zone.northWest.x, zone.southEast.x, 1 do
                local creature = getTopCreature({x = px, y = py, z = pz}).uid

                if creature then
                    data.count.creatures = data.count.creatures + 1
                    data.creatures[i] = creature

                    if isMonster(creature) then
                        data.count.monsters = data.count.monsters + 1
                        data.keys.monsters[#data.keys.monsters+1] = i

                    elseif isPlayer(creature) then
                        data.count.creatures = data.count.creatures + 1
                        data.keys.players[#data.keys.players+1] = i

                    else -- its an NPC
                        data.count.npcs = data.count.npcs + 1
                        data.keys.npcs[#data.keys.npcs+1] = i
                    end

                    i = i + 1 -- Increment key index of creature
                end
            end
        end
    end
    return data
end

Returns the populated version of the data table initialized in the start of the function. Counts creatures, which of them are monsters, players, npcs. Return a creature table with all the cids incase you want to do something else with them. As well as filter/index tables. (the keys tables) which you can look to specifically grab the group you are interested in.

Etc loop through all players in a 5x5x3 area:
Lua:
local fromPos = {x = 95 , y = 95 , z = 6} -- doesn't have to be lowest values
local toPos   = {x = 105, y = 105, z = 8} -- doesn't have to be highest values

local data = getCreatures(fromPos, toPos)

print("Found ".. data.count.players .." players between ["..fromPos.x..","..fromPos.y..","..fromPos.z.."] and ["..toPos.x..","..toPos.y..","..toPos.z.."]")
if data.count.players > 0 then
    for i, key in pairs(data.keys.players) do
        local cid = data.creatures[key]
        local pos = getCreaturePosition(cid)
        print(i..": Found player: "..getCreatureName(cid).." at position: ["..pos.x..","..pos.y..","..pos.z.."].")
    end
end
 
Could be done much simpler using getSpectators which actually gets every creature in the case they are stacked
Lua:
function getCreatures(centerPos, x, y, multifloor)
    local data = {
        monsters = {},
        players = {},
        npcs = {},
        creatures = getSpectators(centerPos, x, y, multifloor)
    }
    for _, creature_id in ipairs(data.creatures) do
        if isMonster(creature_id) then
            data.monsters[#data.monsters + 1] = creature_id
        elseif isPlayer(creature_id) then
            data.players[#data.players + 1] = creature_id
        elseif isNpc(creature_id) then
            data.npcs[#data.npcs + 1] = creature_id
        end
    end
    return data
end

-- Get all creature data within a 10x10 square from center position
local area_data = getCreatures({x = 1000, y = 1000, z = 7}, 10, 10, false)
print(#area_data.monsters) -- Prints the amount of monsters in that area
 
@Snavy Nice, but you forgot to loop through z. You might wanna use that function for something else than groun floor (z = 7).

Had some fun and made a more "generic" multi-purpose getCreatures function based on your code:
Lua:
function getCreatures(fromPos, toPos)
    -- No matter what corner from and to is, we want to make
    -- life easier by calculating north-west and south-east (before we start looping)
    local zone = {
        northWest = {
            x = (fromPos.x < toPos.x and fromPos.x or toPos.x),
            y = (fromPos.y < toPos.y and fromPos.y or toPos.y),
            z = (fromPos.z < toPos.z and fromPos.z or toPos.z)
        },
        southEast = {
            x = (toPos.x > fromPos.x and toPos.x or fromPos.x),
            y = (toPos.y > fromPos.y and toPos.y or fromPos.y),
            z = (toPos.z > fromPos.z and toPos.z or fromPos.z)
        }
    }
    -- data to be returned once populated
    local data = {
        count = {
            creatures = 0,
            monsters = 0,
            players = 0,
            npcs = 0
        },
        keys = {
            monsters = {},
            players = {},
            npcs = {}
        },
        creatures = {}
    }
    -- scan area and populate the data table above
    local i = 1
    for pz = zone.northWest.z, zone.southEast.z, 1 do
        for py = zone.northWest.y, zone.southEast.y, 1 do
            for px = zone.northWest.x, zone.southEast.x, 1 do
                local creature = getTopCreature({x = px, y = py, z = pz}).uid

                if creature then
                    data.count.creatures = data.count.creatures + 1
                    data.creatures[i] = creature

                    if isMonster(creature) then
                        data.count.monsters = data.count.monsters + 1
                        data.keys.monsters[#data.keys.monsters+1] = i

                    elseif isPlayer(creature) then
                        data.count.creatures = data.count.creatures + 1
                        data.keys.players[#data.keys.players+1] = i

                    else -- its an NPC
                        data.count.npcs = data.count.npcs + 1
                        data.keys.npcs[#data.keys.npcs+1] = i
                    end

                    i = i + 1 -- Increment key index of creature
                end
            end
        end
    end
    return data
end

Returns the populated version of the data table initialized in the start of the function. Counts creatures, which of them are monsters, players, npcs. Return a creature table with all the cids incase you want to do something else with them. As well as filter/index tables. (the keys tables) which you can look to specifically grab the group you are interested in.

Etc loop through all players in a 5x5x3 area:
Lua:
local fromPos = {x = 95 , y = 95 , z = 6} -- doesn't have to be lowest values
local toPos   = {x = 105, y = 105, z = 8} -- doesn't have to be highest values

local data = getCreatures(fromPos, toPos)

print("Found ".. data.count.players .." players between ["..fromPos.x..","..fromPos.y..","..fromPos.z.."] and ["..toPos.x..","..toPos.y..","..toPos.z.."]")
if data.count.players > 0 then
    for i, key in pairs(data.keys.players) do
        local cid = data.creatures[key]
        local pos = getCreaturePosition(cid)
        print(i..": Found player: "..getCreatureName(cid).." at position: ["..pos.x..","..pos.y..","..pos.z.."].")
    end
end

Amazing modification :D Will definitely use that in the future.
 
Could be done much simpler using getSpectators which actually gets every creature in the case they are stacked
Lua:
function getCreatures(centerPos, x, y, multifloor)
    local data = {
        monsters = {},
        players = {},
        npcs = {},
        creatures = getSpectators(centerPos, x, y, multifloor)
    }
    for _, creature_id in ipairs(data.creatures) do
        if isMonster(creature_id) then
            data.monsters[#data.monsters + 1] = creature_id
        elseif isPlayer(creature_id) then
            data.players[#data.players + 1] = creature_id
        elseif isNpc(creature_id) then
            data.npcs[#data.npcs + 1] = creature_id
        end
    end
    return data
end

-- Get all creature data within a 10x10 square from center position
local area_data = getCreatures({x = 1000, y = 1000, z = 7}, 10, 10, false)
print(#area_data.monsters) -- Prints the amount of monsters in that area

Does TFS 0.4 have getSpectators? and does it work the same way as in newer tfs's?
 
Back
Top