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

TalkAction [TFS 1.2+] Minimap generator (map scanner)

Gesior.pl

Mega Noob&LOL 2012
Senator
Joined
Sep 18, 2007
Messages
2,955
Solutions
98
Reaction score
3,351
Location
Poland
GitHub
gesior
I've needed Minimap for Tibia client, so I wrote script that teleports player to all possible positions in given area.

It's also good to scan map for possible client debugs. It detects only basic 'wrong items', but I found one debug on my map.

It scans 30 positions per second. You can edit addEventDelay and teleportsPerEvent, but too low interval or too many teleports per event may debug client.
I've tested 30 positions per second and it did not debug client.

On 173MB RL map there around 1130k possible positions.
One Tibia client can scan up to 100k per hour, but you can run few clients at once, each one on other floor. If you do so, remember to reduce maxEventExecutionTime to some low value (100/500) or client will get message about disconnection from server (server will freez for too long).

data/talkactions/talkactions.xml
XML:
    <talkaction words="/minimap" separator=" " script="minimap_scan.lua" />

data/talkactions/scripts/minimap_scan.lua
Lua:
local distanceBetweenPositionsX = 8
local distanceBetweenPositionsY = 8
local addEventDelay = 100
local teleportsPerEvent = 3
local maxEventExecutionTime = 1000

local function teleportToClosestPosition(player, x, y, z)
   -- direct to position
   local tile = Tile(x, y, z)

   if not tile or not tile:getGround() or tile:hasFlag(TILESTATE_TELEPORT) or not player:teleportTo(tile:getPosition()) then
      for distance = 1, 3 do
         -- try to find some close tile
         for changeX = -distance, distance, distance do
            for changeY = -distance, distance, distance do
               tile = Tile(x + changeX, y + changeY, z)
               if tile and tile:getGround() and not tile:hasFlag(TILESTATE_TELEPORT) and player:teleportTo(tile:getPosition()) then
                  return true
               end
            end
         end
      end

      return false
   end

   return true
end

local function sendScanProgress(player, minX, maxX, minY, maxY, x, y, z, lastProgress)
   local progress = math.floor(((y - minY + (((x - minX) / (maxX - minX)) * distanceBetweenPositionsY)) / (maxY - minY)) * 100)
   if progress ~= lastProgress then
      player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, 'Scan progress: ~' .. progress .. '%')
   end

   return progress
end

local function minimapScan(cid, minX, maxX, minY, maxY, x, y, z, lastProgress)
   local player = Player(cid)

   if not player then
      --print('Minimap scan stopped - player logged out', cid, minX, maxX, minY, maxY, x, y, z)
      return
   end

   local scanStartTime = os.mtime()
   local teleportsDone = 0
   while true do
      if scanStartTime + maxEventExecutionTime < os.mtime() then
         lastProgress = sendScanProgress(player, minX, maxX, minY, maxY, x, y, z, lastProgress)
         addEvent(minimapScan, addEventDelay, cid, minX, maxX, minY, maxY, x, y, z, lastProgress)
         break
      end

      x = x + distanceBetweenPositionsX
      if x > maxX then
         x = minX
         y = y + distanceBetweenPositionsY
         if y > maxY then
            player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, 'Scan finished: ' .. os.time())
            --print('Minimap scan complete', player:getName(), minX, maxX, minY, maxY, x, y, z)
            break
         end
      end

      if teleportToClosestPosition(player, x, y, z) then
         teleportsDone = teleportsDone + 1
         lastProgress = sendScanProgress(player, minX, maxX, minY, maxY, x, y, z, lastProgress)

         --print('Minimap scan teleport', player:getName(), minX, maxX, minY, maxY, x, y, z, progress, teleportsDone)
         if teleportsDone == teleportsPerEvent then
            addEvent(minimapScan, addEventDelay, cid, minX, maxX, minY, maxY, x, y, z, progress)
            break
         end
      end
   end
end

local function minimapStart(player, minX, maxX, minY, maxY, x, y, z)
   player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, 'Scan started: ' .. os.time())
   --print('Minimap scan start', player:getName(), minX, maxX, minY, maxY, x, y, z)
   minimapScan(player:getId(), minX, maxX, minY, maxY, minX - 5, minY, z)
end

function onSay(player, words, param)
   if player:getGroup():getId() <= 4 then
      player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, 'Only GOD can scan map. Too low Player group.')
      return false
   end

   if player:getAccountType() < ACCOUNT_TYPE_GAMEMASTER then
      player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, 'Only GOD can scan map.Too low Account type.')
      return false
   end

   local positions = param:split(',')
   if #positions ~= 5 then
      player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, 'Command requires 5 parameters: /minimap minX, maxX, minY, maxY, z')
      return false
   end

   for key, position in pairs(positions) do
      local value = tonumber(position)

      if not value then
         player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, 'Invalid parameter ' .. key .. ': ' .. position)
         return false
      end

      positions[key] = value
   end

   minimapStart(player, positions[1], positions[2], positions[3], positions[4], positions[1] - distanceBetweenPositionsX, positions[3], positions[5])
   return false
end

Example use:
/minimap minX, maxX, minY, maxY, z
/minimap 0, 40000, 0, 40000, 7

EDIT:
TFS 0.4 version:

Lua:
local distanceBetweenPositionsX = 8
local distanceBetweenPositionsY = 8
local addEventDelay = 100
local teleportsPerEvent = 3 -- reduce to 1, if you get client debugs
local maxEventExecutionTime = 1

local function isWalkable(pos)
    if tile and getTileThingByPos(tile) then
        if getTileThingByPos({x = pos.x, y = pos.y, z = pos.z, stackpos = 0}).itemid == 0 then
            return false
        elseif isCreature(getTopCreature(pos).uid) then
            return false
        elseif getTileInfo(pos).protection then
            return false
        elseif hasProperty(getThingFromPos(pos).uid, 3) or hasProperty(getThingFromPos(pos).uid, 7) then
            return false
        end
    end
    return true
end

local function teleportToClosestPosition(cid, x, y, z)
    -- direct to position
    local tile = {x = x, y = y, z = z, stackpos=253}

    if not tile or not getTileThingByPos(tile) or not isWalkable(tile) or not doTeleportThing(cid, tile) then

        for distance = 1, 3 do
            -- try to find some close tile
            for changeX = -distance, distance, distance do
                for changeY = -distance, distance, distance do
                    tile = {x = x + changeX, y = y + changeY, z = z}
                    if tile and getTileThingByPos(tile) and isWalkable(tile) and doTeleportThing(cid, tile) then
                        return true
                    end
                end
            end
        end

        return false
    end

    return true
end

local function sendScanProgress(cid, minX, maxX, minY, maxY, x, y, z, lastProgress)
    local progress = math.floor(((y - minY + (((x - minX) / (maxX - minX)) * distanceBetweenPositionsY)) / (maxY - minY)) * 100)
    if progress ~= lastProgress then
        doPlayerSendTextMessage(cid,MESSAGE_STATUS_CONSOLE_ORANGE, 'Scan progress: ~' .. progress .. '%')
        doPlayerSendTextMessage(cid,MESSAGE_STATUS_CONSOLE_ORANGE, 'X = ' .. x .. 'Y = ' .. y)

    end

    return progress
end

local function minimapScan(cid, minX, maxX, minY, maxY, x, y, z, lastProgress)
    local player = isPlayer(cid)

    if not player then
        print('Minimap scan stopped - player logged out', cid, minX, maxX, minY, maxY, x, y, z)
        return
    end

    local scanStartTime = os.time()
    local teleportsDone = 0
    while true do
        if scanStartTime + maxEventExecutionTime < os.time() then
            lastProgress = sendScanProgress(cid, minX, maxX, minY, maxY, x, y, z, lastProgress)
            addEvent(minimapScan, addEventDelay, cid, minX, maxX, minY, maxY, x, y, z, lastProgress)
            break
        end

        x = x + distanceBetweenPositionsX
        if x > maxX then
            x = minX
            y = y + distanceBetweenPositionsY
            if y > maxY then
                doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, 'Scan finished: ' .. os.time())
                --print('Minimap scan complete', player:getName(), minX, maxX, minY, maxY, x, y, z)
                break
            end
        end

        if teleportToClosestPosition(cid, x, y, z) then
            teleportsDone = teleportsDone + 1
            lastProgress = sendScanProgress(cid, minX, maxX, minY, maxY, x, y, z, lastProgress)

            --print('Minimap scan teleport', player:getName(), minX, maxX, minY, maxY, x, y, z, progress, teleportsDone)
            if teleportsDone == teleportsPerEvent then
                addEvent(minimapScan, addEventDelay, cid, minX, maxX, minY, maxY, x, y, z, progress)
                break
            end
        end
    end
end

local function minimapStart(cid, minX, maxX, minY, maxY, x, y, z)
    doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, 'Scan started: ' .. os.time())
    --print('Minimap scan start', player:getName(), minX, maxX, minY, maxY, x, y, z)
    minimapScan(cid, minX, maxX, minY, maxY, minX - 5, minY, z)
end

function onSay(cid, words, param, channel)
    if getPlayerGroupId(cid) <= 4 then
        doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, 'Only GOD can scan map. Too low Player group.')
        return false
    end

    local positions = string.explode(param, ",")
    if #positions ~= 5 then
        doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, 'Command requires 5 parameters: /minimap minX, maxX, minY, maxY, z')
        return false
    end

    for key, position in pairs(positions) do
        local value = tonumber(position)

        if not value then
            doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, 'Invalid parameter ' .. key .. ': ' .. position)
            return false
        end

        positions[key] = value
    end

    minimapStart(cid, positions[1], positions[2], positions[3], positions[4], positions[1] - distanceBetweenPositionsX, positions[3], positions[5])
    return false
end
 
Last edited:
One Tibia client can scan up to 100k per hour, but you can run few clients at once, each one on other floor.
But it won't save minimap if you use multiple clients at once, right? Or will it?
 
But it won't save minimap if you use multiple clients at once, right? Or will it?
Up to 10.x client it created files with names like:
13213107.map
Name format is:
xxx - 132 * 256 (all tiles with X between '132 * 256' and '132 * 256 + 255' are stored in this file)
yyy - 131 * 256
zz - 7

Client modifies these files in real time, as player sees new tiles in client. It does not modify files of other 'floors'. I ran 2 clients in same time with scans of floor 5 and 6. It created files:
15:51 13112405.map
15:52 13112406.map
15:51 13112505.map
15:52 13112605.map
15:50 13212205.map
15:51 13212206.map

I also ran scanner with parameters:
local distanceBetweenPositionsX = 8
local distanceBetweenPositionsY = 6
and:
local distanceBetweenPositionsX = 12
local distanceBetweenPositionsY = 8
First config worked for 59 minutes to scan 'floor 7' (ground). Second worked for only 23 minutes. Second scanner scanned 99.5% of map.
If you don't have some '3 tile width tunnels with no border around' (NULL tiles around that tunnel), it will scan every possible place on map and take much less time.
 
I see. I still live in the word of client <10.0 that's why I am asking.
Good job, like, really.
 
I see. I still live in the word of client <10.0 that's why I am asking.
Good job, like, really.
7.6, 8.0, 8.6, 9.6, 10.99 - all old clients use that format of map files, so you can even run 16 clients to scan all floors at once.

Updated first post. Just calculated that the best parameters are 8 and 8. It will scan every possible tile on map (closest position algorithm looks 3 tiles around).

EDIT:
I've scanned 16 levels of 173 MB RL map in 33 minutes using 12 MCs. Of course most of time took scan of level 7 (ground).
 
Last edited:
Would you have as converter to 0.4? or would it take up a lot of your time? Thank you, success!
 
omg does it still works? i am trying for otbr but does not work :( ,

Lua:
local minimap = TalkAction("/minimap")

local distanceBetweenPositionsX = 8
local distanceBetweenPositionsY = 8
local addEventDelay = 100
local teleportsPerEvent = 3
local maxEventExecutionTime = 1000

local function teleportToClosestPosition(player, x, y, z)
   -- direct to position
   local tile = Tile(x, y, z)

   if not tile or not tile:getGround() or tile:hasFlag(TILESTATE_TELEPORT) or not player:teleportTo(tile:getPosition()) then
      for distance = 1, 3 do
         -- try to find some close tile
         for changeX = -distance, distance, distance do
            for changeY = -distance, distance, distance do
               tile = Tile(x + changeX, y + changeY, z)
               if tile and tile:getGround() and not tile:hasFlag(TILESTATE_TELEPORT) and player:teleportTo(tile:getPosition()) then
                  return true
               end
            end
         end
      end

      return false
   end

   return true
end

local function sendScanProgress(player, minX, maxX, minY, maxY, x, y, z, lastProgress)
   local progress = math.floor(((y - minY + (((x - minX) / (maxX - minX)) * distanceBetweenPositionsY)) / (maxY - minY)) * 100)
   if progress ~= lastProgress then
      player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, 'Scan progress: ~' .. progress .. '%')
   end

   return progress
end

local function minimapScan(cid, minX, maxX, minY, maxY, x, y, z, lastProgress)
   local player = Player(cid)

   if not player then
      --print('Minimap scan stopped - player logged out', cid, minX, maxX, minY, maxY, x, y, z)
      return
   end

   local scanStartTime = os.mtime()
   local teleportsDone = 0
   while true do
      if scanStartTime + maxEventExecutionTime < os.mtime() then
         lastProgress = sendScanProgress(player, minX, maxX, minY, maxY, x, y, z, lastProgress)
         addEvent(minimapScan, addEventDelay, cid, minX, maxX, minY, maxY, x, y, z, lastProgress)
         break
      end

      x = x + distanceBetweenPositionsX
      if x > maxX then
         x = minX
         y = y + distanceBetweenPositionsY
         if y > maxY then
            player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, 'Scan finished: ' .. os.time())
            --print('Minimap scan complete', player:getName(), minX, maxX, minY, maxY, x, y, z)
            break
         end
      end

      if teleportToClosestPosition(player, x, y, z) then
         teleportsDone = teleportsDone + 1
         lastProgress = sendScanProgress(player, minX, maxX, minY, maxY, x, y, z, lastProgress)

         --print('Minimap scan teleport', player:getName(), minX, maxX, minY, maxY, x, y, z, progress, teleportsDone)
         if teleportsDone == teleportsPerEvent then
            addEvent(minimapScan, addEventDelay, cid, minX, maxX, minY, maxY, x, y, z, progress)
            break
         end
      end
   end
end

minimap:separator(" ")
minimap:register()
 
Lua:
local distanceBetweenPositionsX = 8
local distanceBetweenPositionsY = 8
local addEventDelay = 100
local teleportsPerEvent = 3
local maxEventExecutionTime = 1000

local function isWalkable(pos)
   if tile and getTileThingByPos(tile) then
      if getTileThingByPos({x = pos.x, y = pos.y, z = pos.z, stackpos = 0}).itemid == 0 then
         return false
      elseif isCreature(getTopCreature(pos).uid) then
         return false
      elseif getTileInfo(pos).protection then
         return false
      elseif hasProperty(getThingFromPos(pos).uid, 3) or hasProperty(getThingFromPos(pos).uid, 7) then
         return false
      end
   end
    return true
end

local function teleportToClosestPosition(cid, x, y, z)
   -- direct to position
   local tile = {x = x, y = y, z = z, stackpos=253}

   if not tile or not getTileThingByPos(tile) or not isWalkable(tile) or not doTeleportThing(cid, tile) then
      
      for distance = 1, 3 do
         -- try to find some close tile
         for changeX = -distance, distance, distance do
            for changeY = -distance, distance, distance do
               tile = {x = x + changeX, y = y + changeY, z = z}
               if tile and getTileThingByPos(tile) and isWalkable(tile) and doTeleportThing(cid, tile) then
                  return true
               end
            end
         end
      end

      return false
   end

   return true
end

local function sendScanProgress(cid, minX, maxX, minY, maxY, x, y, z, lastProgress)
   local progress = math.floor(((y - minY + (((x - minX) / (maxX - minX)) * distanceBetweenPositionsY)) / (maxY - minY)) * 100)
   if progress ~= lastProgress then
        doPlayerSendTextMessage(cid,MESSAGE_STATUS_CONSOLE_ORANGE, 'Scan progress: ~' .. progress .. '%')
        doPlayerSendTextMessage(cid,MESSAGE_STATUS_CONSOLE_ORANGE, 'X = ' .. x .. 'Y = ' .. y)

   end

   return progress
end

local function minimapScan(cid, minX, maxX, minY, maxY, x, y, z, lastProgress)
   local player = isPlayer(cid)

   if not player then
      print('Minimap scan stopped - player logged out', cid, minX, maxX, minY, maxY, x, y, z)
      return
   end

   local scanStartTime = os.mtime()
   local teleportsDone = 0
   while true do
      if scanStartTime + maxEventExecutionTime < os.mtime() then
         lastProgress = sendScanProgress(cid, minX, maxX, minY, maxY, x, y, z, lastProgress)
         addEvent(minimapScan, addEventDelay, cid, minX, maxX, minY, maxY, x, y, z, lastProgress)
         break
      end

      x = x + distanceBetweenPositionsX
      if x > maxX then
         x = minX
         y = y + distanceBetweenPositionsY
         if y > maxY then
            doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, 'Scan finished: ' .. os.time())
            --print('Minimap scan complete', player:getName(), minX, maxX, minY, maxY, x, y, z)
            break
         end
      end

      if teleportToClosestPosition(cid, x, y, z) then
         teleportsDone = teleportsDone + 1
         lastProgress = sendScanProgress(cid, minX, maxX, minY, maxY, x, y, z, lastProgress)

         --print('Minimap scan teleport', player:getName(), minX, maxX, minY, maxY, x, y, z, progress, teleportsDone)
         if teleportsDone == teleportsPerEvent then
            addEvent(minimapScan, addEventDelay, cid, minX, maxX, minY, maxY, x, y, z, progress)
            break
         end
      end
   end
end

local function minimapStart(cid, minX, maxX, minY, maxY, x, y, z)
    doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, 'Scan started: ' .. os.time())
   --print('Minimap scan start', player:getName(), minX, maxX, minY, maxY, x, y, z)
   minimapScan(cid, minX, maxX, minY, maxY, minX - 5, minY, z)
end

function onSay(cid, words, param)
   if getPlayerGroupId(cid) <= 4 then
        doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, 'Only GOD can scan map. Too low Player group.')
      return false
   end

   local positions = string.explode(param, ",")
   if #positions ~= 5 then
        doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, 'Command requires 5 parameters: /minimap minX, maxX, minY, maxY, z')
      return false
   end

   for key, position in pairs(positions) do
      local value = tonumber(position)

      if not value then
         doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, 'Invalid parameter ' .. key .. ': ' .. position)
         return false
      end

      positions[key] = value
   end

   minimapStart(cid, positions[1], positions[2], positions[3], positions[4], positions[1] - distanceBetweenPositionsX, positions[3], positions[5])
   return false
end

I tried translating to 0.x versions but i stuck on :
Bash:
data/talkactions/scripts/mapscan.lua:111: attempt to get length of local 'positions' (a nil value)
stack traceback:
    data/talkactions/scripts/mapscan.lua:111: in function <data/talkactions/scripts/mapscan.lua:104>

Any ideas ?
 
Hey guys, I used this function in TFS 1.2 some time ago and it worked, but now I'm moving to Hellgrave 12.72 OTX and I was wondering if someone has already made a working version of this script for OTX.

Thanks and merry christmas,
 
I would like to thank you, I managed to transform the script into revscript and it works as it should, except for an error that returns to the console during execution, but nothing that will affect the result.

Below is the script adapted to revscript:
minimap_generator.lua
Lua:
local distanceBetweenPositionsX = 8
local distanceBetweenPositionsY = 8
local addEventDelay = 100
local teleportsPerEvent = 3
local maxEventExecutionTime = 1000

local function teleportToClosestPosition(player, x, y, z)
    local tile = Tile(x, y, z)
    if not tile or not tile:getGround() or tile:hasFlag(TILESTATE_TELEPORT) or not player:teleportTo(tile:getPosition()) then
        for distance = 1, 3 do
            for changeX = -distance, distance, distance do
                for changeY = -distance, distance, distance do
                    tile = Tile(x + changeX, y + changeY, z)
                    if tile and tile:getGround() and not tile:hasFlag(TILESTATE_TELEPORT) and player:teleportTo(tile:getPosition()) then
                        return true
                    end
                end
            end
        end
        return false
    end
    return true
end

local function sendScanProgress(player, minX, maxX, minY, maxY, x, y, z, lastProgress)
    local progress = math.floor(((y - minY + (((x - minX) / (maxX - minX)) * distanceBetweenPositionsY)) / (maxY - minY)) * 100)
    if progress ~= lastProgress then
        player:sendTextMessage(MESSAGE_STATUS_WARNING, "Scan progress: " .. progress .. "%")
    end

    return progress
end

local function minimapScan(cid, minX, maxX, minY, maxY, x, y, z, lastProgress)
    local player = Player(cid)
    if not player then
        return false
    end

    local scanStartTime = os.mtime()
    local teleportsDone = 0
    while true do
        if scanStartTime + maxEventExecutionTime < os.mtime() then
            lastProgress = sendScanProgress(player, minX, maxX, minY, maxY, x, y, z, lastProgress)
            addEvent(minimapScan, addEventDelay, cid, minX, maxX, minY, maxY, x, y, z, lastProgress)
            break
        end

        x = x + distanceBetweenPositionsX
        if x > maxX then
            x = minX
            y = y + distanceBetweenPositionsY
            if y > maxY then
                player:sendTextMessage(MESSAGE_STATUS_WARNING, "Scan finished: " .. os.time())
                break
            end
        end

        if teleportToClosestPosition(player, x, y, z) then
            teleportsDone = teleportsDone + 1
            lastProgress = sendScanProgress(player, minX, maxX, minY, maxY, x, y, z, lastProgress)
            if teleportsDone == teleportsPerEvent then
                addEvent(minimapScan, addEventDelay, cid, minX, maxX, minY, maxY, x, y, z, progress)
                break
            end
        end
    end
end

local function minimapStart(player, minX, maxX, minY, maxY, x, y, z)
    player:sendTextMessage(MESSAGE_STATUS_WARNING, "Scan started: " .. os.time())
    minimapScan(player:getId(), minX, maxX, minY, maxY, minX - 5, minY, z)
end

local talk = TalkAction("/minimap")

function talk.onSay(player, words, param)
    if not player:getGroup():getAccess() or player:getAccountType() < ACCOUNT_TYPE_GAMEMASTER then
        return false
    end

    local positions = param:split(",")
    if #positions ~= 5 then
        player:sendTextMessage(MESSAGE_STATUS_WARNING, "Command requires 5 parameters: /minimap minX, maxX, minY, maxY, z")
        return false
    end

    for key, position in pairs(positions) do
        local value = tonumber(position)

        if not value then
            player:sendTextMessage(MESSAGE_STATUS_WARNING, "Invalid parameter " .. key .. ": " .. position)
            return false
        end

        positions[key] = value
    end

    minimapStart(player, positions[1], positions[2], positions[3], positions[4], positions[1] - distanceBetweenPositionsX, positions[3], positions[5])
    return false
end

talk:separator(" ")
talk:register()

Error returned when using the script:
Code:
Lua Script Error: [Main Interface]
in a timer event called from:
(Unknown scriptfile)
LuaScriptInterface::getNumber(). Argument 2 has out-of-range value for unsigned short: -3
stack traceback:
        ...-yurots\data\scripts\customsystems\minimap_generator.lua:13: in function 'teleportToClosestPosition'
        ...-yurots\data\scripts\customsystems\minimap_generator.lua:59: in function <...-yurots\data\scripts\customsystems\minimap_generator.lua:34>
 
I would like to thank you, I managed to transform the script into revscript and it works as it should, except for an error that returns to the console during execution, but nothing that will affect the result.

Below is the script adapted to revscript:
minimap_generator.lua
Lua:
local distanceBetweenPositionsX = 8
local distanceBetweenPositionsY = 8
local addEventDelay = 100
local teleportsPerEvent = 3
local maxEventExecutionTime = 1000

local function teleportToClosestPosition(player, x, y, z)
    local tile = Tile(x, y, z)
    if not tile or not tile:getGround() or tile:hasFlag(TILESTATE_TELEPORT) or not player:teleportTo(tile:getPosition()) then
        for distance = 1, 3 do
            for changeX = -distance, distance, distance do
                for changeY = -distance, distance, distance do
                    tile = Tile(x + changeX, y + changeY, z)
                    if tile and tile:getGround() and not tile:hasFlag(TILESTATE_TELEPORT) and player:teleportTo(tile:getPosition()) then
                        return true
                    end
                end
            end
        end
        return false
    end
    return true
end

local function sendScanProgress(player, minX, maxX, minY, maxY, x, y, z, lastProgress)
    local progress = math.floor(((y - minY + (((x - minX) / (maxX - minX)) * distanceBetweenPositionsY)) / (maxY - minY)) * 100)
    if progress ~= lastProgress then
        player:sendTextMessage(MESSAGE_STATUS_WARNING, "Scan progress: " .. progress .. "%")
    end

    return progress
end

local function minimapScan(cid, minX, maxX, minY, maxY, x, y, z, lastProgress)
    local player = Player(cid)
    if not player then
        return false
    end

    local scanStartTime = os.mtime()
    local teleportsDone = 0
    while true do
        if scanStartTime + maxEventExecutionTime < os.mtime() then
            lastProgress = sendScanProgress(player, minX, maxX, minY, maxY, x, y, z, lastProgress)
            addEvent(minimapScan, addEventDelay, cid, minX, maxX, minY, maxY, x, y, z, lastProgress)
            break
        end

        x = x + distanceBetweenPositionsX
        if x > maxX then
            x = minX
            y = y + distanceBetweenPositionsY
            if y > maxY then
                player:sendTextMessage(MESSAGE_STATUS_WARNING, "Scan finished: " .. os.time())
                break
            end
        end

        if teleportToClosestPosition(player, x, y, z) then
            teleportsDone = teleportsDone + 1
            lastProgress = sendScanProgress(player, minX, maxX, minY, maxY, x, y, z, lastProgress)
            if teleportsDone == teleportsPerEvent then
                addEvent(minimapScan, addEventDelay, cid, minX, maxX, minY, maxY, x, y, z, progress)
                break
            end
        end
    end
end

local function minimapStart(player, minX, maxX, minY, maxY, x, y, z)
    player:sendTextMessage(MESSAGE_STATUS_WARNING, "Scan started: " .. os.time())
    minimapScan(player:getId(), minX, maxX, minY, maxY, minX - 5, minY, z)
end

local talk = TalkAction("/minimap")

function talk.onSay(player, words, param)
    if not player:getGroup():getAccess() or player:getAccountType() < ACCOUNT_TYPE_GAMEMASTER then
        return false
    end

    local positions = param:split(",")
    if #positions ~= 5 then
        player:sendTextMessage(MESSAGE_STATUS_WARNING, "Command requires 5 parameters: /minimap minX, maxX, minY, maxY, z")
        return false
    end

    for key, position in pairs(positions) do
        local value = tonumber(position)

        if not value then
            player:sendTextMessage(MESSAGE_STATUS_WARNING, "Invalid parameter " .. key .. ": " .. position)
            return false
        end

        positions[key] = value
    end

    minimapStart(player, positions[1], positions[2], positions[3], positions[4], positions[1] - distanceBetweenPositionsX, positions[3], positions[5])
    return false
end

talk:separator(" ")
talk:register()

Error returned when using the script:
Code:
Lua Script Error: [Main Interface]
in a timer event called from:
(Unknown scriptfile)
LuaScriptInterface::getNumber(). Argument 2 has out-of-range value for unsigned short: -3
stack traceback:
        ...-yurots\data\scripts\customsystems\minimap_generator.lua:13: in function 'teleportToClosestPosition'
        ...-yurots\data\scripts\customsystems\minimap_generator.lua:59: in function <...-yurots\data\scripts\customsystems\minimap_generator.lua:34>
It expects an unsigned value. So if the initial x or y < 3, then its going to produce a negative integer.

Either make sure you dont include the pos 0,0 - 2,2 or just change lines 13-16 to this to remove the error:
Lua:
local checkX = x + changeX
local checkY = y + changeY

if checkX >= 0 and checkY >= 0 then
    tile = Tile(checkX, checkY, z)
    if tile and tile:getGround() and not tile:hasFlag(TILESTATE_TELEPORT) and player:teleportTo(tile:getPosition()) then
        return true
    end
end
 
Back
Top