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
data/talkactions/scripts/minimap_scan.lua
Example use:
EDIT:
TFS 0.4 version:
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: